home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / ZIP_1_0.lha / src / amigaio.c next >
C/C++ Source or Header  |  1992-10-09  |  77KB  |  3,930 lines

  1. /* amigaio.c ******************************************************************
  2.  *
  3.  *    Minimal  Amiga  interface  for Mark Howell's `ZIP' Infocom Interpreter
  4.  *    Program.  This is public-domain, no distribution restrictions apply.
  5.  *
  6.  *    Written by Olaf `Olsen' Barthel, 4 October 1992
  7.  *
  8.  *       This  minimal  interface is guaranteed to work both unter Kickstart
  9.  *    1.2/1.3 and Kickstart 2.0 (or higher if you can afford it).
  10.  *
  11.  *    The  screen drag bar is left intact, it is reduced to four lines.  The
  12.  *    input  procedure  uses the following keys:
  13.  *
  14.  *    Return.............. Terminates input
  15.  *    Control-X........... Erases the input line
  16.  *    Backspace........... Deletes the character to the left of the cursor
  17.  *    Delete.............. Deletes the character under the cursor
  18.  *    Cursor left......... Moves the cursor to the left
  19.  *    Shift cursor left... Moves the cursor to the beginning of the line
  20.  *    Cursor right........ Moves the cursor to the right
  21.  *    Shift cursor right.. Moves the cursor to the end of the line
  22.  *    Cursor up........... Moves up in history list
  23.  *    Shift cursor up..... Moves to first history line
  24.  *    Cursor down......... Moves down in history list
  25.  *    Shift cursor down... Moves to end of history list
  26.  *    Help................ Define function key
  27.  *    F1-F10.............. Function keys
  28.  *    Numeric keypad...... Movement
  29.  *
  30.  *    An  ANSI  `C'  compatible  compiler is required to compile this source
  31.  *    code  (e.g.  SAS/C 5.x, Aztec C 5.x, DICE, GCC).
  32.  *
  33.  *****************************************************************************/
  34.  
  35. #include <intuition/intuitionbase.h>
  36. #include <libraries/dosextens.h>
  37. #include <workbench/workbench.h>
  38. #include <workbench/startup.h>
  39. #include <graphics/gfxbase.h>
  40. #include <devices/conunit.h>
  41. #include <devices/audio.h>
  42. #include <devices/timer.h>
  43. #include <exec/memory.h>
  44.  
  45. #ifdef __GNUC__
  46. #include <inline/stubs.h>
  47.  
  48. #include <inline/intuition.h>
  49. #include <inline/graphics.h>
  50. #include <inline/exec.h>
  51. #include <inline/dos.h>
  52.  
  53. #include <signal.h>
  54.  
  55.     /* Signals to trap while running. */
  56.  
  57. #define TRAPPED_SIGNALS (sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGILL)|sigmask(SIGTRAP)|sigmask(SIGABRT)|sigmask(SIGEMT)|sigmask(SIGFPE)|sigmask(SIGBUS)|sigmask(SIGSEGV)|sigmask(SIGSYS)|sigmask(SIGALRM)|sigmask(SIGTERM)|sigmask(SIGTSTP))
  58.  
  59. #endif    /* __GNUC__ */
  60.  
  61. #include <clib/intuition_protos.h>
  62. #include <clib/graphics_protos.h>
  63. #include <clib/console_protos.h>
  64. #include <clib/icon_protos.h>
  65. #include <clib/alib_protos.h>
  66. #include <clib/exec_protos.h>
  67. #include <clib/dos_protos.h>
  68.  
  69.     /* Some help to keep the code size down. */
  70.  
  71. #ifdef AZTEC_C
  72. #include <pragmas/exec_lib.h>
  73. #endif    /* AZTEC_C */
  74.  
  75. #ifdef LATTICE
  76. #include <pragmas/exec_pragmas.h>
  77. #endif    /* LATTICE */
  78.  
  79. #include <stdarg.h>
  80.  
  81. #include "ztypes.h"
  82.  
  83.     /* Disable ^C trapping for several Amiga `C' compilers. */
  84.  
  85. #ifdef LATTICE
  86. ULONG CXBRK(VOID) { return(0); }
  87. #endif    /* LATTICE */
  88.  
  89. #ifdef AZTEC_C
  90. LONG Chk_Abort(VOID) { return(0); }
  91. VOID _wb_parse(VOID) {}
  92. #endif    /* AZTEC_C */
  93.  
  94.     /* Version identifier tag. */
  95.  
  96. STATIC char            *VersionTag = "\0$VER: AmigaZIP 2.2 (9.10.92)";
  97.  
  98.     /* Control sequence introducer. */
  99.  
  100. #define TERM_CSI        0x9B
  101.  
  102.     /* Backspace character. */
  103.  
  104. #define TERM_BS            '\b'
  105.  
  106.     /* Delete character. */
  107.  
  108. #define TERM_DEL        0x7F
  109.  
  110.     /* Return character. */
  111.  
  112. #define TERM_CR            '\r'
  113.  
  114.     /* Control-X */
  115.  
  116. #define TERM_X            0x18
  117.  
  118.     /* Margin between screen top and window top. */
  119.  
  120. #define SCREEN_MARGIN        4
  121.  
  122.     /* How many history lines to keep. */
  123.  
  124. #ifndef HISTORY_LINES
  125. #define HISTORY_LINES        20
  126. #endif    /* !HISTORY_LINES */
  127.  
  128.     /* Number of function keys. */
  129.  
  130. #define NUM_FKEYS        20
  131.  
  132.     /* Length of `fake' input string. */
  133.  
  134. #define INPUT_LENGTH        1024
  135.  
  136.     /* Minimum system software release version. */
  137.  
  138. #define LIB_VERSION        33
  139.  
  140.     /* A second measured in microseconds. */
  141.  
  142. #define SECOND            1000000
  143.  
  144.     /* Two signals to wait for. */
  145.  
  146. #define SIG_WINDOW        (1 << Window -> UserPort -> mp_SigBit)
  147. #define SIG_TIMER        (1 << TimePort -> mp_SigBit)
  148.  
  149.     /* Audio channel bits. */
  150.  
  151. #define LEFT0F  1
  152. #define RIGHT0F  2
  153. #define RIGHT1F  4
  154. #define LEFT1F  8
  155.  
  156.     /* The two windows. */
  157.  
  158. enum    {    WINDOW_TEXT,WINDOW_STATUS };
  159.  
  160.     /* Cursor widths. */
  161.  
  162. enum    {    CURSOR_AVERAGE = -1,CURSOR_NOCHANGE = 0 };
  163.  
  164.     /* History structure. */
  165.  
  166. struct StringEntry
  167. {
  168.     int    Len;        /* Length of the string. */
  169.     STRPTR    Buffer;        /* The string itself. */
  170. };
  171.  
  172.     /* Global libraries (don't touch!) */
  173.  
  174. struct IntuitionBase        *IntuitionBase;
  175. struct GfxBase            *GfxBase;
  176. struct Library            *IconBase;
  177. struct Device            *ConsoleDevice;
  178.  
  179.     /* Workbench startup message. */
  180.  
  181. STATIC struct WBStartup        *WBenchMsg;
  182.  
  183.     /* Screen and window data. */
  184.  
  185. STATIC struct Screen        *Screen;
  186. STATIC struct Window        *Window;
  187. STATIC struct RastPort        *RPort;
  188.  
  189.     /* Console IO data. */
  190.  
  191. STATIC struct IOStdReq        *ConRequest;
  192. STATIC struct InputEvent    *InputEvent;
  193. STATIC STRPTR             InputEventBuffer;
  194.  
  195. STATIC LONG             CursorX,
  196.                  CursorY,
  197.                  LastX,
  198.                  LastY,
  199.                  OldWidth,
  200.                  NewWidth,
  201.                  WindowWidth;
  202. STATIC BOOL             CursorState,
  203.                  Redraw;
  204.  
  205. STATIC LONG             SavedX,SavedY;
  206. STATIC BOOL             SavedCursor = FALSE;
  207.  
  208.     /* Two different fonts. */
  209.  
  210. STATIC struct TextFont        *PropFont,
  211.                 *FixedFont,
  212.                 *ThisFont;
  213.  
  214.     /* Text font dimensions. */
  215.  
  216. STATIC UWORD             TextFontWidth,
  217.                  TextFontHeight,
  218.                  TextFontAverage;
  219.  
  220.     /* Console data. */
  221.  
  222. STATIC UBYTE             ConChar;
  223. STATIC char            *ConLine;
  224. STATIC int             ConLineLength,
  225.                  ConLineMaxLength,
  226.                  ConLineMinLength;
  227.  
  228. STATIC int             ConFgPen,
  229.                  ConBgPen;
  230.  
  231.     /* Timer data. */
  232.  
  233. STATIC struct MsgPort        *TimePort;
  234. STATIC struct timerequest    *TimeRequest;
  235.  
  236.     /* Process and DOS tricks. */
  237.  
  238. STATIC struct Process        *ThisProcess;
  239. STATIC APTR             WindowPtr;
  240.  
  241.     /* History management. */
  242.  
  243. STATIC struct StringEntry     HistoryBuffer[HISTORY_LINES];
  244. STATIC int             LastHistory = -1;
  245.  
  246.     /* Function key support. */
  247.  
  248. STATIC struct StringEntry     FunctionKeys[NUM_FKEYS];
  249.  
  250.     /* Fake input buffer. */
  251.  
  252. STATIC UBYTE             InputBuffer[INPUT_LENGTH];
  253. STATIC STRPTR             InputIndex;
  254.  
  255.     /* The currently active text window. */
  256.  
  257. STATIC int             CurrentWindow = WINDOW_TEXT;
  258.  
  259.     /* Current game file name and interpreter program name. */
  260.  
  261. STATIC STRPTR             StoryName,
  262.                  InterpreterName;
  263.  
  264.     /* Current text attribute. */
  265.  
  266. STATIC int             CurrentAttribute = NORMAL;
  267.  
  268.     /* Sound support. */
  269.  
  270. STATIC struct IOAudio        *SoundRequestLeft,
  271.                 *SoundRequestRight,
  272.                 *SoundControlRequest;
  273. STATIC struct MsgPort        *SoundPort;
  274.  
  275.     /* Sound file search path. */
  276.  
  277. STATIC char            *SoundName,
  278.                 *SoundPath;
  279.  
  280.     /* Sound data storage. */
  281.  
  282. STATIC int             SoundNumber = -1;
  283. STATIC APTR             SoundData;
  284. STATIC LONG             SoundLength;
  285.  
  286.     /* Custom routines, local. */
  287.  
  288. STATIC BYTE            SoundInit(VOID);
  289. STATIC VOID            SoundExit(VOID);
  290. STATIC VOID            SoundAbort(VOID);
  291. STATIC VOID            SoundStop(VOID);
  292. STATIC VOID            SoundStart(VOID);
  293.  
  294. STATIC WORD            ConCharWidth(const UBYTE Char);
  295. STATIC VOID            ConCursorOff(VOID);
  296. STATIC VOID            ConCursorOn(const int New);
  297. STATIC VOID            ConMove(const int Delta,const int New);
  298. STATIC VOID            ConSet(const int X,const int Y,const int New);
  299. STATIC VOID            ConClearEOL(VOID);
  300. STATIC VOID            ConCharBackspace(const int Delta,const int New);
  301. STATIC VOID            ConCharDelete(const int New);
  302. STATIC VOID            ConCharInsert(const UBYTE Char);
  303. STATIC VOID            ConScrollUp(VOID);
  304. STATIC VOID            ConWrite(char *Line,int Len);
  305. STATIC VOID            ConRedraw(const int X,const int Y,const STRPTR String,const int Len);
  306. STATIC VOID            ConSetKey(int Key,STRPTR String,int Len);
  307. STATIC VOID            ConFlush(VOID);
  308. STATIC UBYTE            ConGetChar(BOOL SingleKey);
  309. STATIC VOID            ConPrintf(char *Format,...);
  310. STATIC int            ConInput(char *Prompt,char *Input,int MaxLen,BOOL DoHistory);
  311.  
  312.     /* SoundInit():
  313.      *
  314.      *    Allocate resources for sound routine.
  315.      */
  316.  
  317. STATIC BYTE
  318. SoundInit()
  319. {
  320.         /* Create io reply port. */
  321.  
  322.     if(SoundPort = (struct MsgPort *)CreatePort(NULL,0))
  323.     {
  324.             /* Create io control request. We will use it
  325.              * later to change the volume of a sound.
  326.              */
  327.  
  328.         if(SoundControlRequest = (struct IOAudio *)CreateExtIO(SoundPort,sizeof(struct IOAudio)))
  329.         {
  330.                 /* Create io request for left channel. */
  331.  
  332.             if(SoundRequestLeft = (struct IOAudio *)CreateExtIO(SoundPort,sizeof(struct IOAudio)))
  333.             {
  334.                     /* Create io request for right channel. */
  335.  
  336.                 if(SoundRequestRight = (struct IOAudio *)CreateExtIO(SoundPort,sizeof(struct IOAudio)))
  337.                 {
  338.                         /* Channel allocation map,
  339.                          * we want any two stereo
  340.                          * channels.
  341.                          */
  342.  
  343.                     STATIC UBYTE AllocationMap[] =
  344.                     {
  345.                         LEFT0F | RIGHT0F,
  346.                         LEFT0F | RIGHT1F,
  347.                         LEFT1F | RIGHT0F,
  348.                         LEFT1F | RIGHT1F
  349.                     };
  350.  
  351.                         /* Set it up for channel allocation,
  352.                          * any two stereo channels will do.
  353.                          */
  354.  
  355.                     SoundControlRequest -> ioa_Request . io_Message . mn_Node . ln_Pri    = 127;
  356.                     SoundControlRequest -> ioa_Request . io_Command                = ADCMD_ALLOCATE;
  357.                     SoundControlRequest -> ioa_Request . io_Flags                = ADIOF_NOWAIT | ADIOF_PERVOL;
  358.                     SoundControlRequest -> ioa_Data                        = AllocationMap;
  359.                     SoundControlRequest -> ioa_Length                    = sizeof(AllocationMap);
  360.  
  361.                         /* Open the device, allocating the channel on the way. */
  362.  
  363.                     if(!OpenDevice(AUDIONAME,NULL,(struct IORequest *)SoundControlRequest,NULL))
  364.                     {
  365.                             /* Copy the initial data to the
  366.                              * other audio io requests.
  367.                              */
  368.  
  369.                         CopyMem((BYTE *)SoundControlRequest,(BYTE *)SoundRequestLeft, sizeof(struct IOAudio));
  370.                         CopyMem((BYTE *)SoundControlRequest,(BYTE *)SoundRequestRight,sizeof(struct IOAudio));
  371.  
  372.                             /* Divide the channels. */
  373.  
  374.                         SoundRequestLeft  -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestLeft  -> ioa_Request . io_Unit & (LEFT0F  | LEFT1F));
  375.                         SoundRequestRight -> ioa_Request . io_Unit = (struct Unit *)((ULONG)SoundRequestRight -> ioa_Request . io_Unit & (RIGHT0F | RIGHT1F));
  376.  
  377.                             /* Return success. */
  378.  
  379.                         return(TRUE);
  380.                     }
  381.                 }
  382.             }
  383.         }
  384.     }
  385.  
  386.         /* Clean up... */
  387.  
  388.     SoundExit();
  389.  
  390.         /* ...and return failure. */
  391.  
  392.     return(FALSE);
  393. }
  394.  
  395.     /* SoundExit():
  396.      *
  397.      *    Free resources allocated by SoundInit().
  398.      */
  399.  
  400. STATIC VOID
  401. SoundExit()
  402. {
  403.         /* Free the left channel data. */
  404.  
  405.     if(SoundRequestLeft)
  406.     {
  407.             /* Did we open the device? */
  408.  
  409.         if(SoundRequestLeft -> ioa_Request . io_Device)
  410.         {
  411.                 /* Check if the sound is still playing. */
  412.  
  413.             if(!CheckIO((struct IORequest *)SoundRequestLeft))
  414.             {
  415.                     /* Abort the request. */
  416.  
  417.                 AbortIO((struct IORequest *)SoundRequestLeft);
  418.  
  419.                     /* Wait for it to return. */
  420.  
  421.                 WaitIO((struct IORequest *)SoundRequestLeft);
  422.             }
  423.             else
  424.                 GetMsg(SoundPort);
  425.         }
  426.  
  427.             /* Free the memory allocated. */
  428.  
  429.         DeleteExtIO((struct IORequest *)SoundRequestLeft);
  430.  
  431.             /* Leave no traces. */
  432.  
  433.         SoundRequestLeft = NULL;
  434.     }
  435.  
  436.         /* Free the right channel data. */
  437.  
  438.     if(SoundRequestRight)
  439.     {
  440.             /* Did we open the device? */
  441.  
  442.         if(SoundRequestRight -> ioa_Request . io_Device)
  443.         {
  444.                 /* Check if the sound is still playing. */
  445.  
  446.             if(!CheckIO((struct IORequest *)SoundRequestRight))
  447.             {
  448.                     /* Abort the request. */
  449.  
  450.                 AbortIO((struct IORequest *)SoundRequestRight);
  451.  
  452.                     /* Wait for it to return. */
  453.  
  454.                 WaitIO((struct IORequest *)SoundRequestRight);
  455.             }
  456.             else
  457.                 GetMsg(SoundPort);
  458.         }
  459.  
  460.             /* Free the memory allocated. */
  461.  
  462.         DeleteExtIO((struct IORequest *)SoundRequestRight);
  463.  
  464.             /* Leave no traces. */
  465.  
  466.         SoundRequestRight = NULL;
  467.     }
  468.  
  469.         /* Free sound control request. */
  470.  
  471.     if(SoundControlRequest)
  472.     {
  473.             /* Close the device, free any allocated channels. */
  474.  
  475.         if(SoundControlRequest -> ioa_Request . io_Device)
  476.             CloseDevice((struct IORequest *)SoundControlRequest);
  477.  
  478.             /* Free the memory allocated. */
  479.  
  480.         DeleteExtIO((struct IORequest *)SoundControlRequest);
  481.  
  482.             /* Leave no traces. */
  483.  
  484.         SoundControlRequest = NULL;
  485.     }
  486.  
  487.         /* Free sound io reply port. */
  488.  
  489.     if(SoundPort)
  490.     {
  491.             /* Delete it. */
  492.  
  493.         DeletePort(SoundPort);
  494.  
  495.             /* Leave no traces. */
  496.  
  497.         SoundPort = NULL;
  498.     }
  499.  
  500.         /* Free sound data. */
  501.  
  502.     if(SoundData && SoundLength)
  503.     {
  504.             /* Free it. */
  505.  
  506.         FreeMem(SoundData,SoundLength);
  507.  
  508.             /* Leave no traces. */
  509.  
  510.         SoundData    = NULL;
  511.         SoundLength    = 0;
  512.     }
  513.  
  514.         /* Clear current sound number. */
  515.  
  516.     SoundNumber = -1;
  517. }
  518.  
  519.     /* SoundAbort():
  520.      *
  521.      *    Abort any currently playing sound and wait for
  522.      *    both IORequests to return.
  523.      */
  524.  
  525. STATIC VOID
  526. SoundAbort()
  527. {
  528.         /* Abort sound playing on the left channel. */
  529.  
  530.     if(!CheckIO((struct IORequest *)SoundRequestLeft))
  531.         AbortIO((struct IORequest *)SoundRequestLeft);
  532.  
  533.         /* Wait for the request to return. */
  534.  
  535.     WaitIO((struct IORequest *)SoundRequestLeft);
  536.  
  537.         /* Abort sound playing on the right channel. */
  538.  
  539.     if(!CheckIO((struct IORequest *)SoundRequestRight))
  540.         AbortIO((struct IORequest *)SoundRequestRight);
  541.  
  542.         /* Wait for the request to return. */
  543.  
  544.     WaitIO((struct IORequest *)SoundRequestRight);
  545. }
  546.  
  547.     /* SoundStop():
  548.      *
  549.      *    Stop sound from getting played (somewhat equivalent to ^S).
  550.      */
  551.  
  552. STATIC VOID
  553. SoundStop()
  554. {
  555.         /* Fill in the command. */
  556.  
  557.     SoundControlRequest -> ioa_Request . io_Command = CMD_STOP;
  558.  
  559.         /* Send it off. */
  560.  
  561.     SendIO((struct IORequest *)SoundControlRequest);
  562.     WaitIO((struct IORequest *)SoundControlRequest);
  563. }
  564.  
  565.     /* SoundStart():
  566.      *
  567.      *    Restart any queued sound.
  568.      */
  569.  
  570. STATIC VOID
  571. SoundStart()
  572. {
  573.         /* Fill in the command. */
  574.  
  575.     SoundControlRequest -> ioa_Request . io_Command = CMD_START;
  576.  
  577.         /* Send it off. */
  578.  
  579.     SendIO((struct IORequest *)SoundControlRequest);
  580.     WaitIO((struct IORequest *)SoundControlRequest);
  581. }
  582.  
  583.     /* ConCharWidth(const UBYTE Char):
  584.      *
  585.      *    Calculate the pixel width of a glyph.
  586.      */
  587.  
  588. STATIC WORD
  589. ConCharWidth(const UBYTE Char)
  590. {
  591.     return(TextLength(RPort,(STRPTR)&Char,1));
  592. }
  593.  
  594.     /* ConCursorOff():
  595.      *
  596.      *    Turn the terminal cursor on.
  597.      */
  598.  
  599. STATIC VOID
  600. ConCursorOff()
  601. {
  602.         /* Is it still enabled? */
  603.  
  604.     if(CursorState)
  605.     {
  606.             /* Remove the cursor. */
  607.  
  608.         SetAPen(RPort,0xFF);
  609.         SetDrMd(RPort,COMPLEMENT|JAM2);
  610.  
  611.         RectFill(RPort,LastX,LastY,LastX + NewWidth - 1,LastY + TextFontHeight - 1);
  612.  
  613.         SetAPen(RPort,ConFgPen);
  614.         SetDrMd(RPort,JAM2);
  615.  
  616.             /* It's turned off now. */
  617.  
  618.         CursorState = FALSE;
  619.     }
  620. }
  621.  
  622.     /* ConCursorOn(const int New):
  623.      *
  624.      *    Turn the terminal cursor off.
  625.      */
  626.  
  627. STATIC VOID
  628. ConCursorOn(const int New)
  629. {
  630.         /* Is it still disabled? */
  631.  
  632.     if(!CursorState)
  633.     {
  634.             /* Remember new cursor width. */
  635.  
  636.         switch(New)
  637.         {
  638.             case CURSOR_NOCHANGE:    break;
  639.  
  640.             case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  641.                         break;
  642.  
  643.             default:        NewWidth = New;
  644.                         break;
  645.         }
  646.  
  647.             /* Turn the cursor back on. */
  648.  
  649.         SetAPen(RPort,0xFF);
  650.         SetDrMd(RPort,COMPLEMENT|JAM2);
  651.  
  652.         RectFill(RPort,CursorX,CursorY,CursorX + NewWidth - 1,CursorY + TextFontHeight - 1);
  653.  
  654.         SetAPen(RPort,ConFgPen);
  655.         SetDrMd(RPort,JAM2);
  656.  
  657.             /* Remember cursor width. */
  658.  
  659.         OldWidth = NewWidth;
  660.  
  661.             /* It's turn on now. */
  662.  
  663.         CursorState = TRUE;
  664.  
  665.             /* Remember cursor position. */
  666.  
  667.         LastX = CursorX;
  668.         LastY = CursorY;
  669.     }
  670. }
  671.  
  672.     /* ConMove(const int Delta,const int New):
  673.      *
  674.      *    Move the cursor.
  675.      */
  676.  
  677. STATIC VOID
  678. ConMove(const int Delta,const int New)
  679. {
  680.         /* If the cursor is still enabled, turn it
  681.          * off before repositioning it.
  682.          */
  683.  
  684.     if(CursorState)
  685.     {
  686.             /* Turn the cursor off. */
  687.  
  688.         ConCursorOff();
  689.  
  690.             /* Move it. */
  691.  
  692.         CursorX += Delta;
  693.  
  694.             /* Turn the cursor back on. */
  695.  
  696.         ConCursorOn(New);
  697.     }
  698.     else
  699.     {
  700.         switch(New)
  701.         {
  702.             case CURSOR_NOCHANGE:    break;
  703.  
  704.             case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  705.                         break;
  706.  
  707.             default:        NewWidth = New;
  708.                         break;
  709.         }
  710.  
  711.         CursorX += Delta;
  712.     }
  713. }
  714.  
  715.     /* ConSet(const int X,const int Y,const int New):
  716.      *
  717.      *    Place the cursor at a specific position.
  718.      */
  719.  
  720. STATIC VOID
  721. ConSet(const int X,const int Y,const int New)
  722. {
  723.         /* If the cursor is still enabled, turn it
  724.          * off before repositioning it.
  725.          */
  726.  
  727.     if(CursorState)
  728.     {
  729.             /* Turn the cursor off. */
  730.  
  731.         ConCursorOff();
  732.  
  733.             /* Move drawing pen. */
  734.  
  735.         Move(RPort,X,Y + ThisFont -> tf_Baseline);
  736.  
  737.             /* Position the cursor. */
  738.  
  739.         CursorX = X;
  740.         CursorY = Y;
  741.  
  742.             /* Turn the cursor back on. */
  743.  
  744.         ConCursorOn(New);
  745.     }
  746.     else
  747.     {
  748.             /* Remember new cursor width. */
  749.  
  750.         switch(New)
  751.         {
  752.             case CURSOR_NOCHANGE:    break;
  753.  
  754.             case CURSOR_AVERAGE:    NewWidth = OldWidth = TextFontAverage;
  755.                         break;
  756.  
  757.             default:        NewWidth = OldWidth = New;
  758.                         break;
  759.         }
  760.  
  761.             /* Move drawing pen. */
  762.  
  763.         Move(RPort,X,Y + ThisFont -> tf_Baseline);
  764.  
  765.             /* Position the cursor. */
  766.  
  767.         CursorX = X;
  768.         CursorY = Y;
  769.     }
  770. }
  771.  
  772.     /* ConClearEOL():
  773.      *
  774.      *    Clear to end of current line.
  775.      */
  776.  
  777. STATIC VOID
  778. ConClearEOL()
  779. {
  780.         /* Is there anything to clear? */
  781.  
  782.     if(CursorX < WindowWidth)
  783.     {
  784.             /* Turn the cursor off before the line is cleared. */
  785.  
  786.         if(CursorState)
  787.         {
  788.                 /* Turn the cursor off. */
  789.  
  790.             ConCursorOff();
  791.  
  792.                 /* Clear the remaining line. */
  793.  
  794.             SetAPen(RPort,0);
  795.             RectFill(RPort,CursorX,CursorY,Window -> Width - 1,CursorY + TextFontHeight - 1);
  796.             SetAPen(RPort,ConFgPen);
  797.  
  798.                 /* Turn the cursor back on. */
  799.  
  800.             ConCursorOn(CURSOR_NOCHANGE);
  801.         }
  802.         else
  803.         {
  804.             SetAPen(RPort,0);
  805.             RectFill(RPort,CursorX,CursorY,Window -> Width - 1,CursorY + TextFontHeight - 1);
  806.             SetAPen(RPort,ConFgPen);
  807.         }
  808.     }
  809. }
  810.  
  811.     /* ConCharBackspace(const int Delta,const int New):
  812.      *
  813.      *    Move the cursor one glyph back.
  814.      */
  815.  
  816. STATIC VOID
  817. ConCharBackspace(const int Delta,const int New)
  818. {
  819.     Redraw = TRUE;
  820.  
  821.     CursorX -= Delta;
  822.  
  823.     switch(New)
  824.     {
  825.         case CURSOR_NOCHANGE:    break;
  826.  
  827.         case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  828.                     break;
  829.  
  830.         default:        NewWidth = New;
  831.                     break;
  832.     }
  833. }
  834.  
  835.     /* ConCharDelete(const int New):
  836.      *
  837.      *    Delete the character under the cursor.
  838.      */
  839.  
  840. STATIC VOID
  841. ConCharDelete(const int New)
  842. {
  843.     Redraw = TRUE;
  844.  
  845.     switch(New)
  846.     {
  847.         case CURSOR_NOCHANGE:    break;
  848.  
  849.         case CURSOR_AVERAGE:    NewWidth = TextFontAverage;
  850.                     break;
  851.  
  852.         default:        NewWidth = New;
  853.                     break;
  854.     }
  855. }
  856.  
  857.     /* ConCharInsert(const UBYTE Char):
  858.      *
  859.      *    Insert a character at the current cursor position.
  860.      */
  861.  
  862. STATIC VOID
  863. ConCharInsert(const UBYTE Char)
  864. {
  865.     Redraw = TRUE;
  866.  
  867.     CursorX += ConCharWidth(Char);
  868. }
  869.  
  870.     /* ConScrollUp():
  871.      *
  872.      *    Scroll the terminal contents one line up.
  873.      */
  874.  
  875. STATIC VOID
  876. ConScrollUp()
  877. {
  878.     UWORD Top = status_size * TextFontHeight;
  879.  
  880.         /* Is the cursor enabled? */
  881.  
  882.     if(CursorState)
  883.     {
  884.             /* Turn the cursor off. */
  885.  
  886.         ConCursorOff();
  887.  
  888.             /* Scroll the terminal contents up. */
  889.  
  890.         ScrollRaster(RPort,0,TextFontHeight,0,Top,Window -> Width - 1,Window -> Height - 1);
  891.  
  892.             /* Reposition the cursor. */
  893.  
  894.         CursorX = 0;
  895.         CursorY = TextFontHeight * (screen_rows - 1);
  896.  
  897.             /* Turn it on again. */
  898.  
  899.         ConCursorOn(CURSOR_NOCHANGE);
  900.     }
  901.     else
  902.     {
  903.             /* Scroll the terminal contents up. */
  904.  
  905.         ScrollRaster(RPort,0,TextFontHeight,0,Top,Window -> Width - 1,Window -> Height - 1);
  906.  
  907.             /* Reposition the cursor. */
  908.  
  909.         CursorX = 0;
  910.         CursorY = TextFontHeight * (screen_rows - 1);
  911.     }
  912. }
  913.  
  914.     /* ConWrite(const char *Line,LONG Len):
  915.      *
  916.      *    Output a text on the terminal.
  917.      */
  918.  
  919. STATIC VOID
  920. ConWrite(char *Line,int Len)
  921. {
  922.         /* Just like console.device, determine the
  923.          * text length if -1 is passed in as the
  924.          * length.
  925.          */
  926.  
  927.     if(Len == -1)
  928.         Len = strlen(Line);
  929.  
  930.         /* Is there anything to print? */
  931.  
  932.     if(Len)
  933.     {
  934.             /* Is the cursor still enabled? */
  935.  
  936.         if(CursorState)
  937.         {
  938.                 /* Turn off the cursor. */
  939.  
  940.             ConCursorOff();
  941.  
  942.                 /* Print the text. */
  943.  
  944.             Move(RPort,CursorX,CursorY + ThisFont -> tf_Baseline);
  945.             Text(RPort,(STRPTR)Line,Len);
  946.  
  947.                 /* Move up. */
  948.  
  949.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  950.  
  951.                 /* Turn the cursor back on. */
  952.  
  953.             ConCursorOn(CURSOR_NOCHANGE);
  954.         }
  955.         else
  956.         {
  957.                 /* Print the text. */
  958.  
  959.             Move(RPort,CursorX,CursorY + ThisFont -> tf_Baseline);
  960.             Text(RPort,(STRPTR)Line,Len);
  961.  
  962.                 /* Move up. */
  963.  
  964.             CursorX += TextLength(RPort,(STRPTR)Line,Len);
  965.         }
  966.     }
  967. }
  968.  
  969.     /* ConRedraw(const int X,const int Y,const STRPTR String,const int Len):
  970.      *
  971.      *    Redraw the input string.
  972.      */
  973.  
  974. STATIC VOID
  975. ConRedraw(const int X,const int Y,const STRPTR String,const int Len)
  976. {
  977.     LONG Width = TextLength(RPort,(STRPTR)String,Len);
  978.  
  979.         /* Turn the cursor off. */
  980.  
  981.     ConCursorOff();
  982.  
  983.         /* Redraw the input string. */
  984.  
  985.     Move(RPort,X,Y + ThisFont -> tf_Baseline);
  986.     Text(RPort,(STRPTR)String,Len);
  987.  
  988.         /* Clear to end of line. */
  989.  
  990.     if(Width < WindowWidth)
  991.     {
  992.         SetAPen(RPort,0);
  993.         RectFill(RPort,X + Width,Y,Window -> Width - 1,Y + TextFontHeight - 1);
  994.         SetAPen(RPort,0);
  995.     }
  996.  
  997.         /* Turn the cursor back on. */
  998.  
  999.     ConCursorOn(CURSOR_NOCHANGE);
  1000. }
  1001.  
  1002.     /* ConSetKey(int Key,STRPTR String,int Len):
  1003.      *
  1004.      *    Set a specific function key.
  1005.      */
  1006.  
  1007. STATIC VOID
  1008. ConSetKey(int Key,STRPTR String,int Len)
  1009. {
  1010.         /* Is the new string longer than the old one? */
  1011.  
  1012.     if(FunctionKeys[Key] . Len < Len)
  1013.     {
  1014.             /* Free previous key assignment. */
  1015.  
  1016.         free(FunctionKeys[Key] . Buffer);
  1017.  
  1018.             /* Create new string buffer. */
  1019.  
  1020.         if(FunctionKeys[Key] . Buffer = (STRPTR)malloc(Len + 1))
  1021.         {
  1022.                 /* Copy the key string. */
  1023.  
  1024.             memcpy(FunctionKeys[Key] . Buffer,String,Len);
  1025.  
  1026.                 /* Provide null-termination. */
  1027.  
  1028.             FunctionKeys[Key] . Buffer[Len] = 0;
  1029.  
  1030.                 /* Set string length. */
  1031.  
  1032.             FunctionKeys[Key] . Len = Len;
  1033.         }
  1034.         else
  1035.             FunctionKeys[Key] . Len = 0;
  1036.     }
  1037.     else
  1038.     {
  1039.             /* Install new string. */
  1040.  
  1041.         if(Len)
  1042.         {
  1043.                 /* Copy the key string. */
  1044.  
  1045.             memcpy(FunctionKeys[Key] . Buffer,String,Len);
  1046.  
  1047.                 /* Provide null-termination. */
  1048.  
  1049.             FunctionKeys[Key] . Buffer[Len] = 0;
  1050.         }
  1051.         else
  1052.         {
  1053.                 /* Zero length, free previous buffer
  1054.                  * assignment.
  1055.                  */
  1056.  
  1057.             if(FunctionKeys[Key] . Buffer)
  1058.             {
  1059.                     /* Free the buffer. */
  1060.  
  1061.                 free(FunctionKeys[Key] . Buffer);
  1062.  
  1063.                     /* Clear address pointer. */
  1064.  
  1065.                 FunctionKeys[Key] . Buffer = NULL;
  1066.             }
  1067.         }
  1068.  
  1069.             /* Install new length. */
  1070.  
  1071.         FunctionKeys[Key] . Len = Len;
  1072.     }
  1073. }
  1074.  
  1075.     /* ConFlush():
  1076.      *
  1077.      *    Flush the text cache.
  1078.      */
  1079.  
  1080. STATIC VOID
  1081. ConFlush()
  1082. {
  1083.         /* Are there any characters in the cache? */
  1084.  
  1085.     if(ConLineLength)
  1086.     {
  1087.         register BYTE HasMore = FALSE;
  1088.  
  1089.             /* Did we get exactly six character? */
  1090.  
  1091.         if(ConLineLength == 6)
  1092.         {
  1093.                 /* Is it the `[MORE]' prompt? */
  1094.  
  1095.             if(!memcmp(ConLine,"[MORE]",6))
  1096.             {
  1097.                     /* Reset text attribute. */
  1098.  
  1099.                 SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  1100.  
  1101.                 if(ConFgPen != 1)
  1102.                     SetAPen(RPort,ConFgPen = 1);
  1103.  
  1104.                 if(ThisFont != PropFont)
  1105.                     SetFont(RPort,ThisFont = PropFont);
  1106.  
  1107.                 HasMore = TRUE;
  1108.             }
  1109.         }
  1110.  
  1111.         if(HasMore)
  1112.         {
  1113.                 /* Flush the cache. */
  1114.  
  1115.             ConWrite(ConLine,ConLineLength);
  1116.  
  1117.                 /* Reset index. */
  1118.  
  1119.             ConLineLength = 0;
  1120.  
  1121.                 /* Turn on original text attributes. */
  1122.  
  1123.             set_attribute(CurrentAttribute);
  1124.         }
  1125.         else
  1126.         {
  1127.                 /* Flush the cache. */
  1128.  
  1129.             ConWrite(ConLine,ConLineLength);
  1130.  
  1131.                 /* Reset index. */
  1132.  
  1133.             ConLineLength = 0;
  1134.         }
  1135.     }
  1136. }
  1137.  
  1138.     /* ConGetChar():
  1139.      *
  1140.      *    Read a single character from the console window.
  1141.      */
  1142.  
  1143. STATIC UBYTE
  1144. ConGetChar(BOOL SingleKey)
  1145. {
  1146.     struct IntuiMessage    *IntuiMessage;
  1147.     ULONG             Qualifier,
  1148.                  Class,
  1149.                  Code,
  1150.                  Signals;
  1151.     LONG             Len;
  1152.  
  1153.         /* Provide `fake' input in case we are
  1154.          * returning the result of a function keypress
  1155.          * or a menu event.
  1156.          */
  1157.  
  1158.     if(InputIndex)
  1159.     {
  1160.             /* Did we reach the end of the string?
  1161.              * If so, clear the index pointer and
  1162.              * fall through to the input routine.
  1163.              * If not, return the next character
  1164.              * in the buffer.
  1165.              */
  1166.  
  1167.         if(*InputIndex)
  1168.             return(*InputIndex++);
  1169.         else
  1170.             InputIndex = NULL;
  1171.     }
  1172.  
  1173.         /* Wait for input... */
  1174.  
  1175.     FOREVER
  1176.     {
  1177.             /* Process all incoming messages. */
  1178.  
  1179.         while(IntuiMessage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1180.         {
  1181.                 /* Remember the menu code. */
  1182.  
  1183.             Qualifier    = IntuiMessage -> Qualifier;
  1184.             Class        = IntuiMessage -> Class;
  1185.             Code        = IntuiMessage -> Code;
  1186.  
  1187.                 /* Conver key code to ANSI character or control sequence. */
  1188.  
  1189.             if(Class == IDCMP_RAWKEY)
  1190.             {
  1191.                 InputEvent -> ie_Class            = IECLASS_RAWKEY;
  1192.                 InputEvent -> ie_Code            = Code;
  1193.                 InputEvent -> ie_Qualifier        = Qualifier;
  1194.                 InputEvent -> ie_position . ie_addr    = *((APTR *)IntuiMessage -> IAddress);
  1195.  
  1196.                 InputEventBuffer[0] = 0;
  1197.  
  1198.                 Len = RawKeyConvert(InputEvent,InputEventBuffer,INPUT_LENGTH - 1,NULL);
  1199.             }
  1200.             else
  1201.                 Len = 0;
  1202.  
  1203.                 /* Reply the message. */
  1204.  
  1205.             ReplyMsg((struct Message *)IntuiMessage);
  1206.  
  1207.                 /* Did the user press a key? */
  1208.  
  1209.             if(Class == IDCMP_RAWKEY && Len > 0)
  1210.             {
  1211.                     /* Provide null-termination. */
  1212.  
  1213.                 InputEventBuffer[Len] = 0;
  1214.  
  1215.                     /* Is this a numeric pad key
  1216.                      * and was no shift key pressed?
  1217.                      */
  1218.  
  1219.                 if(Qualifier & IEQUALIFIER_NUMERICPAD)
  1220.                 {
  1221.                     if(!(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)))
  1222.                     {
  1223.                         if(SingleKey)
  1224.                             return(InputEventBuffer[0]);
  1225.                         else
  1226.                         {
  1227.                                 /* Numbers and associated directions. */
  1228.  
  1229.                             STATIC STRPTR Directions[][2] =
  1230.                             {
  1231.                                 "8",    "n\r",
  1232.                                 "9",    "ne\r",
  1233.                                 "6",    "e\r",
  1234.                                 "3",    "se\r",
  1235.                                 "2",    "s\r",
  1236.                                 "1",    "sw\r",
  1237.                                 "4",    "w\r",
  1238.                                 "7",    "nw\r",
  1239.  
  1240.                                 "[",    "in\r",
  1241.                                 "]",    "out\r",
  1242.  
  1243.                                 "+",    "u\r",
  1244.                                 "-",    "d\r"
  1245.                             };
  1246.  
  1247.                             int i;
  1248.  
  1249.                                 /* Run down the list of directions. */
  1250.  
  1251.                             for(i = 0 ; i < sizeof(Directions) / (2 * sizeof(STRPTR)) ; i++)
  1252.                             {
  1253.                                     /* Does it match the input? */
  1254.  
  1255.                                 if(!strcmp(Directions[i][0],InputEventBuffer))
  1256.                                 {
  1257.                                         /* Use it as fake input. */
  1258.  
  1259.                                     InputIndex = Directions[i][1];
  1260.  
  1261.                                         /* Return ^X. */
  1262.  
  1263.                                     return(TERM_X);
  1264.                                 }
  1265.                             }
  1266.                         }
  1267.                     }
  1268.                 }
  1269.                 else
  1270.                 {
  1271.                     if(SingleKey)
  1272.                     {
  1273.                         if(InputEventBuffer[0] != TERM_CSI)
  1274.                             return(InputEventBuffer[0]);
  1275.                     }
  1276.                     else
  1277.                     {
  1278.                             /* Take over the input. */
  1279.  
  1280.                         InputIndex = InputEventBuffer;
  1281.  
  1282.                             /* Return the first character. */
  1283.  
  1284.                         return(*InputIndex++);
  1285.                     }
  1286.                 }
  1287.             }
  1288.         }
  1289.  
  1290.         do
  1291.         {
  1292.             Signals = Wait(SIG_TIMER | SIG_WINDOW);
  1293.  
  1294.             if(Signals & SIG_TIMER)
  1295.             {
  1296.                 if(CursorState)
  1297.                     ConCursorOff();
  1298.                 else
  1299.                     ConCursorOn(CURSOR_NOCHANGE);
  1300.  
  1301.                     /* Remove timer request. */
  1302.  
  1303.                 WaitIO(TimeRequest);
  1304.  
  1305.                     /* Send new timer request. */
  1306.  
  1307.                 TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1308.                 TimeRequest -> tr_time . tv_secs    = 0;
  1309.                 TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  1310.  
  1311.                 BeginIO(TimeRequest);
  1312.             }
  1313.         }
  1314.         while(!(Signals & SIG_WINDOW));
  1315.     }
  1316. }
  1317.  
  1318.     /* ConPrintf(char *Format,...):
  1319.      *
  1320.      *    Print a text in the console window, including formatting
  1321.      *    control codes.
  1322.      */
  1323.  
  1324. STATIC VOID
  1325. ConPrintf(char *Format,...)
  1326. {
  1327.     STATIC char    ConBuffer[256];
  1328.     va_list        VarArgs;
  1329.  
  1330.     va_start(VarArgs,Format);
  1331.     vsprintf(ConBuffer,Format,VarArgs);
  1332.     va_end(VarArgs);
  1333.  
  1334.     ConWrite(ConBuffer,-1);
  1335. }
  1336.  
  1337.     /* ConInput(char *Input,int MaxLen):
  1338.      *
  1339.      *    Read a line of input from the console window.
  1340.      */
  1341.  
  1342. STATIC int
  1343. ConInput(char *Prompt,char *Input,int MaxLen,BOOL DoHistory)
  1344. {
  1345.         /* Control sequence buffer and length of control sequence. */
  1346.  
  1347.     UBYTE        SequenceBuffer[81];
  1348.     int        SequenceLen;
  1349.  
  1350.         /* Input length, current cursor position index, last history buffer. */
  1351.  
  1352.     register int    Len        = 0,
  1353.             Index        = 0,
  1354.             HistoryIndex    = LastHistory + 1,
  1355.             i;
  1356.  
  1357.         /* The character to read. */
  1358.  
  1359.     register UBYTE    Char;
  1360.  
  1361.         /* Loop flag. */
  1362.  
  1363.     BOOL        Done    = FALSE;
  1364.  
  1365.     UWORD        OldX    = CursorX;
  1366.  
  1367.     if(ThisFont != PropFont)
  1368.     {
  1369.         SetFont(RPort,PropFont);
  1370.  
  1371.         ThisFont = PropFont;
  1372.     }
  1373.  
  1374.     ConCursorOn(CURSOR_AVERAGE);
  1375.  
  1376.         /* Read until done. */
  1377.  
  1378.     do
  1379.     {
  1380.             /* Get a character. */
  1381.  
  1382.         switch(Char = ConGetChar(FALSE))
  1383.         {
  1384.                 /* A function key, a cursor key or the help key. */
  1385.  
  1386.             case TERM_CSI:    SequenceLen = 0;
  1387.  
  1388.                         /* Read the whole sequence if possible,
  1389.                          * up to 80 characters will be accepted.
  1390.                          */
  1391.  
  1392.                     do
  1393.                         SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  1394.                     while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  1395.  
  1396.                         /* Provide null-termination. */
  1397.  
  1398.                     SequenceBuffer[SequenceLen] = 0;
  1399.  
  1400.                         /* Function key. */
  1401.  
  1402.                     if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  1403.                     {
  1404.                         int Key;
  1405.  
  1406.                             /* Remove the terminating tilde. */
  1407.  
  1408.                         SequenceBuffer[SequenceLen - 1] = 0;
  1409.  
  1410.                             /* Make sure that the function
  1411.                              * key code is in reasonable
  1412.                              * dimensions, some custom
  1413.                              * keyboards have more than
  1414.                              * 20 function keys.
  1415.                              */
  1416.  
  1417.                         if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  1418.                         {
  1419.                                 /* Is a string assigned to
  1420.                                  * this function key?
  1421.                                  */
  1422.  
  1423.                             if(FunctionKeys[Key] . Len)
  1424.                             {
  1425.                                 BOOL    GotIt = FALSE;
  1426.                                 int    i;
  1427.  
  1428.                                     /* Examine the string and look
  1429.                                      * for a bar or exclamation mark
  1430.                                      * which will terminate the
  1431.                                      * string and produce a carriage-
  1432.                                      * return.
  1433.                                      */
  1434.  
  1435.                                 for(i = 0 ; i < FunctionKeys[Key] . Len ; i++)
  1436.                                 {
  1437.                                         /* Is this the character we are looking for? */
  1438.  
  1439.                                     if(FunctionKeys[Key] . Buffer[i] == '|' || FunctionKeys[Key] . Buffer[i] == '!')
  1440.                                     {
  1441.                                             /* Copy the string. */
  1442.  
  1443.                                         memcpy(InputBuffer,FunctionKeys[Key] . Buffer,i);
  1444.  
  1445.                                             /* Add the carriage-return. */
  1446.  
  1447.                                         InputBuffer[i++] = '\r';
  1448.                                         InputBuffer[i]   = 0;
  1449.  
  1450.                                             /* Stop the search and
  1451.                                              * remember that we got
  1452.                                              * a fitting string.
  1453.                                              */
  1454.  
  1455.                                         GotIt = TRUE;
  1456.  
  1457.                                         break;
  1458.                                     }
  1459.                                 }
  1460.  
  1461.                                     /* Provide new input. */
  1462.  
  1463.                                 if(GotIt)
  1464.                                     InputIndex = InputBuffer;
  1465.                                 else
  1466.                                     InputIndex = FunctionKeys[Key] . Buffer;
  1467.                             }
  1468.                             else
  1469.                                 DisplayBeep(Window -> WScreen);
  1470.                         }
  1471.  
  1472.                         break;
  1473.                     }
  1474.  
  1475.                         /* Help key. */
  1476.  
  1477.                     if(DoHistory && !strcmp(SequenceBuffer,"?~"))
  1478.                     {
  1479.                             /* Which function key is pressed? */
  1480.  
  1481.                         int WhichKey = -1;
  1482.  
  1483.                             /* Do not produce any `fake' input. */
  1484.  
  1485.                         InputIndex = NULL;
  1486.  
  1487.                         ConCursorOff();
  1488.  
  1489.                             /* Clear the input line. */
  1490.  
  1491.                         ConSet(0,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1492.  
  1493.                             /* Ask for the function key to
  1494.                              * assign a string to.
  1495.                              */
  1496.  
  1497.                         ConPrintf("Function key to define: ");
  1498.                         ConClearEOL();
  1499.  
  1500.                         ConCursorOn(CURSOR_NOCHANGE);
  1501.  
  1502.                             /* Is the first character we get
  1503.                              * a control-sequence introducer?
  1504.                              */
  1505.  
  1506.                         if(ConGetChar(FALSE) == TERM_CSI)
  1507.                         {
  1508.                             SequenceLen = 0;
  1509.  
  1510.                                 /* Read the whole sequence if possible,
  1511.                                  * up to 80 characters will be accepted.
  1512.                                  */
  1513.  
  1514.                             do
  1515.                                 SequenceBuffer[SequenceLen++] = Char = ConGetChar(FALSE);
  1516.                             while(SequenceLen < 80 && (Char == ' ' || Char == ';' || Char == '?' || (Char >= '0' && Char <= '9')));
  1517.  
  1518.                                 /* Provide null-termination. */
  1519.  
  1520.                             SequenceBuffer[SequenceLen] = 0;
  1521.  
  1522.                                 /* Did we get a function key code? */
  1523.  
  1524.                             if(SequenceBuffer[0] != '?' && SequenceBuffer[SequenceLen - 1] == '~')
  1525.                             {
  1526.                                     /* The function key we got. */
  1527.  
  1528.                                 int Key;
  1529.  
  1530.                                     /* Remove the terminating tilde. */
  1531.  
  1532.                                 SequenceBuffer[SequenceLen - 1] = 0;
  1533.  
  1534.                                     /* Get the number of the key. */
  1535.  
  1536.                                 if((Key = atoi(SequenceBuffer)) < NUM_FKEYS)
  1537.                                     WhichKey = Key;
  1538.                             }
  1539.                         }
  1540.  
  1541.                         ConCursorOff();
  1542.  
  1543.                             /* Did we get any key? */
  1544.  
  1545.                         if(WhichKey == -1)
  1546.                             ConPrintf("none.");
  1547.                         else
  1548.                         {
  1549.                             int Len;
  1550.  
  1551.                                 /* Print the key name. */
  1552.  
  1553.                             ConPrintf("%sF%d",(WhichKey > 9) ? "Shift " : "",(WhichKey % 10) + 1);
  1554.  
  1555.                                 /* Provide new line. */
  1556.  
  1557.                             ConScrollUp();
  1558.  
  1559.                                 /* Show new prompt. */
  1560.  
  1561.                             ConPrintf("Key text >");
  1562.  
  1563.                             ConCursorOn(CURSOR_NOCHANGE);
  1564.  
  1565.                             InputIndex = NULL;
  1566.  
  1567.                                 /* Read key assignment. */
  1568.  
  1569.                             Len = ConInput("",InputBuffer,0,FALSE);
  1570.  
  1571.                                 /* Set new key string. */
  1572.  
  1573.                             ConSetKey(WhichKey,InputBuffer,Len);
  1574.  
  1575.                             ConCursorOff();
  1576.                         }
  1577.  
  1578.                             /* Provide new line. */
  1579.  
  1580.                         ConScrollUp();
  1581.  
  1582.                             /* Print the prompt string. */
  1583.  
  1584.                         ConPrintf(Prompt);
  1585.  
  1586.                             /* Write the entire input line. */
  1587.  
  1588.                         ConWrite(Input,Len);
  1589.  
  1590.                             /* Make sure that the
  1591.                              * cursor is placed at
  1592.                              * the end of the input
  1593.                              * line.
  1594.                              */
  1595.  
  1596.                         Index = Len;
  1597.  
  1598.                         InputIndex = NULL;
  1599.  
  1600.                         ConCursorOn(CURSOR_AVERAGE);
  1601.  
  1602.                         break;
  1603.                     }
  1604.  
  1605.                         /* Cursor up: recall previous line in history buffer. */
  1606.  
  1607.                     if(!strcmp(SequenceBuffer,"A"))
  1608.                     {
  1609.                             /* Are any history lines available? */
  1610.  
  1611.                         if(LastHistory != -1)
  1612.                         {
  1613.                             ConCursorOff();
  1614.  
  1615.                                 /* Move cursor back
  1616.                                  * to beginning of
  1617.                                  * line.
  1618.                                  */
  1619.  
  1620.                             if(Index)
  1621.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1622.  
  1623.                                 /* Clear line. */
  1624.  
  1625.                             ConClearEOL();
  1626.  
  1627.                                 /* Go to previous history line. */
  1628.  
  1629.                             if(HistoryIndex)
  1630.                                 HistoryIndex--;
  1631.  
  1632.                                 /* Determine history line length. */
  1633.  
  1634.                             if(MaxLen)
  1635.                                 Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1636.                             else
  1637.                                 Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1638.  
  1639.                                 /* Copy the history line over. */
  1640.  
  1641.                             memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1642.  
  1643.                                 /* Write the line. */
  1644.  
  1645.                             ConWrite(Input,Len);
  1646.  
  1647.                             ConCursorOn(CURSOR_NOCHANGE);
  1648.                         }
  1649.  
  1650.                         break;
  1651.                     }
  1652.  
  1653.                         /* Cursor down: recall next line in history buffer. */
  1654.  
  1655.                     if(!strcmp(SequenceBuffer,"B"))
  1656.                     {
  1657.                             /* Are any history lines available? */
  1658.  
  1659.                         if(LastHistory != -1)
  1660.                         {
  1661.                             ConCursorOff();
  1662.  
  1663.                                 /* Are we at the end
  1664.                                  * of the list?
  1665.                                  */
  1666.  
  1667.                             if(HistoryIndex < LastHistory)
  1668.                             {
  1669.                                     /* Move cursor back
  1670.                                      * to beginning of
  1671.                                      * line.
  1672.                                      */
  1673.  
  1674.                                 if(Index)
  1675.                                     ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1676.  
  1677.                                     /* Clear line. */
  1678.  
  1679.                                 ConClearEOL();
  1680.  
  1681.                                     /* Get next history line. */
  1682.  
  1683.                                 HistoryIndex++;
  1684.  
  1685.                                     /* Determine history line length. */
  1686.  
  1687.                                 if(MaxLen)
  1688.                                     Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1689.                                 else
  1690.                                     Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1691.  
  1692.                                     /* Copy the history line over. */
  1693.  
  1694.                                 memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1695.  
  1696.                                     /* Write the line. */
  1697.  
  1698.                                 ConWrite(Input,Len);
  1699.                             }
  1700.                             else
  1701.                             {
  1702.                                     /* Move cursor back
  1703.                                      * to beginning of
  1704.                                      * line.
  1705.                                      */
  1706.  
  1707.                                 if(Index)
  1708.                                     ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1709.  
  1710.                                     /* Clear line. */
  1711.  
  1712.                                 ConClearEOL();
  1713.  
  1714.                                     /* Nothing in the line buffer right now. */
  1715.  
  1716.                                 Index = Len = 0;
  1717.  
  1718.                                     /* Make sure that `cursor up'
  1719.                                      * will recall the last history
  1720.                                      * line.
  1721.                                      */
  1722.  
  1723.                                 HistoryIndex = LastHistory + 1;
  1724.                             }
  1725.  
  1726.                             ConCursorOn(CURSOR_NOCHANGE);
  1727.                         }
  1728.  
  1729.                         break;
  1730.                     }
  1731.  
  1732.                         /* Shift+cursor up: recall first history line in buffer. */
  1733.  
  1734.                     if(!strcmp(SequenceBuffer,"T"))
  1735.                     {
  1736.                             /* Are any history lines available? */
  1737.  
  1738.                         if(LastHistory != -1)
  1739.                         {
  1740.                             ConCursorOff();
  1741.  
  1742.                                 /* Move cursor back
  1743.                                  * to beginning of
  1744.                                  * line.
  1745.                                  */
  1746.  
  1747.                             if(Index)
  1748.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1749.  
  1750.                                 /* Clear line. */
  1751.  
  1752.                             ConClearEOL();
  1753.  
  1754.                                 /* Use the first history line. */
  1755.  
  1756.                             HistoryIndex = 0;
  1757.  
  1758.                                 /* Determine history line length. */
  1759.  
  1760.                             if(MaxLen)
  1761.                                 Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1762.                             else
  1763.                                 Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1764.  
  1765.                                 /* Copy the history line over. */
  1766.  
  1767.                             memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1768.  
  1769.                                 /* Write the line. */
  1770.  
  1771.                             ConWrite(Input,Len);
  1772.  
  1773.                             ConCursorOn(CURSOR_NOCHANGE);
  1774.                         }
  1775.  
  1776.                         break;
  1777.                     }
  1778.  
  1779.                         /* Shift+cursor down: recall last history line. */
  1780.  
  1781.                     if(!strcmp(SequenceBuffer,"S"))
  1782.                     {
  1783.                             /* Are any history lines available? */
  1784.  
  1785.                         if(LastHistory != -1)
  1786.                         {
  1787.                             ConCursorOff();
  1788.  
  1789.                                 /* Move cursor back
  1790.                                  * to beginning of
  1791.                                  * line.
  1792.                                  */
  1793.  
  1794.                             if(Index)
  1795.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1796.  
  1797.                                 /* Clear line. */
  1798.  
  1799.                             ConClearEOL();
  1800.  
  1801.                                 /* Go to last line in history buffer. */
  1802.  
  1803.                             HistoryIndex = LastHistory;
  1804.  
  1805.                                 /* Determine history line length. */
  1806.  
  1807.                             if(MaxLen)
  1808.                                 Index = Len = (HistoryBuffer[HistoryIndex] . Len > MaxLen) ? MaxLen : HistoryBuffer[HistoryIndex] . Len;
  1809.                             else
  1810.                                 Index = Len = HistoryBuffer[HistoryIndex] . Len;
  1811.  
  1812.                                 /* Copy the history line over. */
  1813.  
  1814.                             memcpy(Input,HistoryBuffer[HistoryIndex] . Buffer,Len);
  1815.  
  1816.                                 /* Write the line. */
  1817.  
  1818.                             ConWrite(Input,Len);
  1819.  
  1820.                             ConCursorOn(CURSOR_NOCHANGE);
  1821.                         }
  1822.  
  1823.                         break;
  1824.                     }
  1825.  
  1826.                         /* Cursor right: move cursor to the right. */
  1827.  
  1828.                     if(!strcmp(SequenceBuffer,"C"))
  1829.                     {
  1830.                             /* Are we at the end of the line? */
  1831.  
  1832.                         if(Index < Len)
  1833.                         {
  1834.                             if(Index == Len - 1)
  1835.                                 ConMove(ConCharWidth(Input[Index]),CURSOR_AVERAGE);
  1836.                             else
  1837.                                 ConMove(ConCharWidth(Input[Index]),ConCharWidth(Input[Index + 1]));
  1838.  
  1839.                             Index++;
  1840.                         }
  1841.  
  1842.                         break;
  1843.                     }
  1844.  
  1845.                         /* Cursor left: move cursor to the left. */
  1846.  
  1847.                     if(!strcmp(SequenceBuffer,"D"))
  1848.                     {
  1849.                             /* Are we at the beginning of the line? */
  1850.  
  1851.                         if(Index > 0)
  1852.                         {
  1853.                                 /* Update internal cursor position. */
  1854.  
  1855.                             Index--;
  1856.  
  1857.                                 /* Move cursor to the left. */
  1858.  
  1859.                             ConMove(-ConCharWidth(Input[Index]),ConCharWidth(Input[Index]));
  1860.                         }
  1861.  
  1862.                         break;
  1863.                     }
  1864.  
  1865.                         /* Shift+cursor right: move cursor to end of line. */
  1866.  
  1867.                     if(!strcmp(SequenceBuffer," @"))
  1868.                     {
  1869.                             /* Are we at the end of the line? */
  1870.  
  1871.                         if(Index < Len)
  1872.                         {
  1873.                                 /* Move cursor to end of line. */
  1874.  
  1875.                             ConMove(TextLength(RPort,&Input[Index],Len - Index),CURSOR_AVERAGE);
  1876.  
  1877.                                 /* Update internal cursor position. */
  1878.  
  1879.                             Index = Len;
  1880.                         }
  1881.  
  1882.                         break;
  1883.                     }
  1884.  
  1885.                         /* Shift+cursor left: move cursor to beginning of line. */
  1886.  
  1887.                     if(!strcmp(SequenceBuffer," A"))
  1888.                     {
  1889.                             /* Are we at the beginning of the line? */
  1890.  
  1891.                         if(Index > 0)
  1892.                         {
  1893.                                 /* Move cursor to beginning of line. */
  1894.  
  1895.                             if(Len)
  1896.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),ConCharWidth(Input[0]));
  1897.                             else
  1898.                                 ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1899.  
  1900.                                 /* Update internal cursor position. */
  1901.  
  1902.                             Index = 0;
  1903.                         }
  1904.                     }
  1905.  
  1906.                     break;
  1907.  
  1908.                 /* Backspace: delete the character to the left
  1909.                  * of the cursor.
  1910.                  */
  1911.  
  1912.             case TERM_BS:    if(Index > 0)
  1913.                     {
  1914.                             /* Delete the character. */
  1915.  
  1916.                         if(Index == Len)
  1917.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),CURSOR_AVERAGE);
  1918.                         else
  1919.                             ConCharBackspace(ConCharWidth(Input[Index - 1]),ConCharWidth(Input[Index]));
  1920.  
  1921.                             /* Move line contents. */
  1922.  
  1923.                         for(i = Index - 1 ; i < Len - 1 ; i++)
  1924.                             Input[i] = Input[i + 1];
  1925.  
  1926.                             /* Update internal cursor position. */
  1927.  
  1928.                         Index--;
  1929.  
  1930.                             /* Update line length. */
  1931.  
  1932.                         Len--;
  1933.                     }
  1934.  
  1935.                     break;
  1936.  
  1937.                 /* Delete: delete the character under the cursor. */
  1938.  
  1939.             case TERM_DEL:    if(Index < Len)
  1940.                     {
  1941.                             /* Delete the character. */
  1942.  
  1943.                         if(Index == Len - 1)
  1944.                             ConCharDelete(CURSOR_AVERAGE);
  1945.                         else
  1946.                             ConCharDelete(ConCharWidth(Input[Index + 1]));
  1947.  
  1948.                             /* Move line contents. */
  1949.  
  1950.                         for(i = Index ; i < Len - 1 ; i++)
  1951.                             Input[i] = Input[i + 1];
  1952.  
  1953.                             /* Update line length. */
  1954.  
  1955.                         Len--;
  1956.                     }
  1957.  
  1958.                     break;
  1959.  
  1960.                 /* Control-X: delete the entire line contents. */
  1961.  
  1962.             case TERM_X:    if(Len > 0)
  1963.                     {
  1964.                             /* Move to beginning of line. */
  1965.  
  1966.                         if(Index)
  1967.                             ConSet(OldX,TextFontHeight * (screen_rows - 1),CURSOR_AVERAGE);
  1968.  
  1969.                             /* Clear line contents. */
  1970.  
  1971.                         ConClearEOL();
  1972.  
  1973.                             /* Nothing in the line buffer right now. */
  1974.  
  1975.                         Index = Len = 0;
  1976.                     }
  1977.  
  1978.                     break;
  1979.  
  1980.                 /* Carriage return: terminate input. */
  1981.  
  1982.             case TERM_CR:    Done = TRUE;
  1983.  
  1984.                     break;
  1985.  
  1986.                 /* If suitable, store the character entered. */
  1987.  
  1988.             default:    if(Char >= 32 && Char < 127)
  1989.                     {
  1990.                             /* Is there a length limit? */
  1991.  
  1992.                         if(MaxLen)
  1993.                         {
  1994.                                 /* If the string is large
  1995.                                  * enough already, don't
  1996.                                  * store the new character.
  1997.                                  */
  1998.  
  1999.                             if(Len >= MaxLen)
  2000.                                 break;
  2001.                         }
  2002.  
  2003.                             /* Is the resulting string too long
  2004.                              * to fit in the window, don't store
  2005.                              * the new character.
  2006.                              */
  2007.  
  2008.                         if(OldX + TextLength(RPort,Input,Len) + TextFontWidth + ConCharWidth(Char) >= WindowWidth)
  2009.                             break;
  2010.  
  2011.                             /* Print the character. */
  2012.  
  2013.                         ConCharInsert(Char);
  2014.  
  2015.                             /* Move line contents up if
  2016.                              * necessary.
  2017.                              */
  2018.  
  2019.                         if(Index < Len)
  2020.                         {
  2021.                             for(i = Len ; i > Index ; i--)
  2022.                                 Input[i] = Input[i - 1];
  2023.                         }
  2024.  
  2025.                             /* Store the character. */
  2026.  
  2027.                         Input[Index++] = Char;
  2028.  
  2029.                             /* Update line length. */
  2030.  
  2031.                         Len++;
  2032.                     }
  2033.  
  2034.                     break;
  2035.         }
  2036.  
  2037.             /* Are we to redraw the input line? */
  2038.  
  2039.         if(Redraw)
  2040.         {
  2041.             ConRedraw(OldX,TextFontHeight * (screen_rows - 1),Input,Len);
  2042.  
  2043.             Redraw = FALSE;
  2044.         }
  2045.     }
  2046.     while(!Done);
  2047.  
  2048.         /* Did the user enter anything? */
  2049.  
  2050.     if(Len && DoHistory)
  2051.     {
  2052.             /* Move up if space is exhausted. */
  2053.  
  2054.         if(LastHistory == HISTORY_LINES - 1)
  2055.         {
  2056.                 /* Free first line in history buffer. */
  2057.  
  2058.             free(HistoryBuffer[0] . Buffer);
  2059.  
  2060.                 /* Move previous contents up. */
  2061.  
  2062.             for(i = 1 ; i < HISTORY_LINES ; i++)
  2063.                 HistoryBuffer[i - 1] = HistoryBuffer[i];
  2064.         }
  2065.         else
  2066.             LastHistory++;
  2067.  
  2068.             /* Add next history line. */
  2069.  
  2070.         if(HistoryBuffer[LastHistory] . Buffer = (char *)malloc(Len))
  2071.         {
  2072.                 /* Copy the input line. */
  2073.  
  2074.             memcpy(HistoryBuffer[LastHistory] . Buffer,Input,Len);
  2075.  
  2076.                 /* Save the line length. */
  2077.  
  2078.             HistoryBuffer[LastHistory] . Len = Len;
  2079.         }
  2080.         else
  2081.             LastHistory--;
  2082.     }
  2083.  
  2084.         /* Return number of characters entered. */
  2085.  
  2086.     return(Len);
  2087. }
  2088.  
  2089.     /* initialize_screen():
  2090.      *
  2091.      *    Set up the screen to display the text.
  2092.      */
  2093.  
  2094. VOID
  2095. initialize_screen()
  2096. {
  2097.         /* Default and system font definitions. */
  2098.  
  2099.     STATIC struct TextAttr     DefaultFont = { (STRPTR)"topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED };
  2100.  
  2101.         /* The buffer to receive a copy of the Workbench screen. */
  2102.  
  2103.     struct Screen         WorkbenchScreen;
  2104.  
  2105.         /* New screen structure. */
  2106.  
  2107.     struct NewScreen     NewScreen;
  2108.  
  2109.         /* New window structure. */
  2110.  
  2111.     struct NewWindow     NewWindow;
  2112.  
  2113.         /* System font dimensions. */
  2114.  
  2115.     UWORD             SystemFontWidth,
  2116.                  SystemFontHeight;
  2117.  
  2118.         /* Auxilary data. */
  2119.  
  2120.     UWORD             Width,Len;
  2121.     UBYTE             Char;
  2122.  
  2123.         /* The famous `The story is loading...' (as seen on television). */
  2124.  
  2125.     const char        *TheStory = "The story is loading...";
  2126.  
  2127. #ifdef __GNUC__
  2128.  
  2129.     sigset_t trapped = TRAPPED_SIGNALS;
  2130.  
  2131.     if(sigprocmask(SIG_BLOCK,&trapped,NULL) != 0)
  2132.         fatal("Could not block signals");
  2133.  
  2134. #endif    /* __GNUC__ */
  2135.  
  2136.         /* Get current process identifier. */
  2137.  
  2138.     ThisProcess = (struct Process *)FindTask(NULL);
  2139.  
  2140.         /* Remember old window pointer. */
  2141.  
  2142.     WindowPtr = ThisProcess -> pr_WindowPtr;
  2143.  
  2144.         /* Open libraries... */
  2145.  
  2146.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",LIB_VERSION)))
  2147.         fatal("Could not open intuition.library");
  2148.  
  2149.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",LIB_VERSION)))
  2150.         fatal("Could not open graphics.library");
  2151.  
  2152.     IconBase = OpenLibrary("icon.library",LIB_VERSION);
  2153.  
  2154.         /* Create timer reply port. */
  2155.  
  2156.     if(!(TimePort = (struct MsgPort *)CreatePort(NULL,0)))
  2157.         fatal("Could not create timer port");
  2158.  
  2159.         /* Create timer IORequest. */
  2160.  
  2161.     if(!(TimeRequest = (struct timerequest *)CreateExtIO(TimePort,sizeof(struct timerequest))))
  2162.         fatal("Could not create timer request");
  2163.  
  2164.         /* Open timer.device. */
  2165.  
  2166.     if(OpenDevice("timer.device",UNIT_VBLANK,(struct IORequest *)TimeRequest,0))
  2167.         fatal("Could not open timer.device");
  2168.  
  2169.         /* Remember current system font. */
  2170.  
  2171.     Forbid();
  2172.  
  2173.         /* Remember system font dimensions. */
  2174.  
  2175.     SystemFontWidth        = GfxBase -> DefaultFont -> tf_XSize;
  2176.     SystemFontHeight    = GfxBase -> DefaultFont -> tf_YSize;
  2177.  
  2178.     Permit();
  2179.  
  2180.         /* Clear new screen definition. */
  2181.  
  2182.     memset(&NewScreen,0,sizeof(struct NewScreen));
  2183.  
  2184.         /* Fill in the common screen data. */
  2185.  
  2186.     NewScreen . Depth    = 1;
  2187.     NewScreen . DetailPen    = 0;
  2188.     NewScreen . BlockPen    = 1;
  2189.     NewScreen . Type    = CUSTOMSCREEN | SCREENBEHIND | SCREENQUIET;
  2190.     NewScreen . Font    = NULL;
  2191.  
  2192.     Forbid();
  2193.  
  2194.         /* Try to get some information on the Workbench screen. */
  2195.  
  2196.     if(GetScreenData(&WorkbenchScreen,sizeof(struct Screen),WBENCHSCREEN,NULL))
  2197.     {
  2198.         UWORD    Height    = WorkbenchScreen . Height,
  2199.             Width    = WorkbenchScreen . Width;
  2200.  
  2201.             /* Pick up the screen display mode ID. */
  2202.  
  2203.         NewScreen . ViewModes = WorkbenchScreen . ViewPort . Modes;
  2204.  
  2205.             /* Check for illegal dimension. */
  2206.  
  2207.         if(Width > 2 * GfxBase -> MaxDisplayColumn)
  2208.             Width = GfxBase -> NormalDisplayColumns;
  2209.  
  2210.         if(NewScreen . ViewModes & LACE)
  2211.         {
  2212.             if(Height > 2 * GfxBase -> MaxDisplayRow)
  2213.                 Height = 2 * GfxBase -> NormalDisplayRows;
  2214.         }
  2215.         else
  2216.         {
  2217.             if(Height > GfxBase -> MaxDisplayRow)
  2218.                 Height = GfxBase -> NormalDisplayRows;
  2219.         }
  2220.  
  2221.         NewScreen . Height = (((Height - SCREEN_MARGIN) / SystemFontHeight) * SystemFontHeight) + SCREEN_MARGIN;
  2222.  
  2223.             /* `A mind forever voyaging' requires a fixed screen
  2224.              * width of eighty characters per line.
  2225.              */
  2226.  
  2227.         if(h_type == 4 && (h_version == 79 || h_version == 77))
  2228.         {
  2229.             if(SystemFontWidth * 80 > Width)
  2230.             {
  2231.                 NewScreen . Width    = 640;
  2232.                 NewScreen . Height    = (((Height - SCREEN_MARGIN) / 8) * 8) + SCREEN_MARGIN;
  2233.                 NewScreen . Font    = &DefaultFont;
  2234.             }
  2235.             else
  2236.                 NewScreen . Width = SystemFontWidth * 80;
  2237.         }
  2238.         else
  2239.         {
  2240.                 /* The current interpreter release does not
  2241.                  * support more than 128 columns.
  2242.                  */
  2243.  
  2244.             if(Width / SystemFontWidth > 128)
  2245.             {
  2246.                 NewScreen . Width    = 640;
  2247.                 NewScreen . Height    = (((Height - SCREEN_MARGIN) / 8) * 8) + SCREEN_MARGIN;
  2248.                 NewScreen . Font    = &DefaultFont;
  2249.             }
  2250.             else
  2251.                 NewScreen . Width = Width;
  2252.         }
  2253.     }
  2254.     else
  2255.     {
  2256.             /* Seems that it went wrong, anyway: let's assume
  2257.              * default values then.
  2258.              */
  2259.  
  2260.         NewScreen . ViewModes = HIRES;
  2261.  
  2262.             /* If the desired screen width is larger
  2263.              * than 640 pixels, use the default font.
  2264.              */
  2265.  
  2266.         if(SystemFontWidth * 80 > 640)
  2267.         {
  2268.             NewScreen . Width    = 640;
  2269.             NewScreen . Font    = &DefaultFont;
  2270.         }
  2271.         else
  2272.             NewScreen . Width = SystemFontWidth * 80;
  2273.  
  2274.             /* Adjust screen height accordingly. */
  2275.  
  2276.         if((GfxBase -> DisplayFlags & (PAL|NTSC)) == PAL)
  2277.             NewScreen . Height = (((256 - SCREEN_MARGIN) / SystemFontHeight) * SystemFontHeight) + SCREEN_MARGIN;
  2278.         else
  2279.             NewScreen . Height = (((200 - SCREEN_MARGIN) / SystemFontHeight) * SystemFontHeight) + SCREEN_MARGIN;
  2280.     }
  2281.  
  2282.     Permit();
  2283.  
  2284.         /* Open the screen. */
  2285.  
  2286.     if(IntuitionBase -> LibNode . lib_Version < 36)
  2287.     {
  2288.         if(!(Screen = (struct Screen *)OpenScreen(&NewScreen)))
  2289.             fatal("Could not open screen");
  2290.  
  2291.             /* Turn off the screen title. */
  2292.  
  2293.         ShowTitle(Screen,FALSE);
  2294.     }
  2295.     else
  2296.     {
  2297.         struct Rectangle    DisplayClip;
  2298.         ULONG            DisplayID;
  2299.  
  2300.         if(NewScreen . ViewModes & LACE)
  2301.             DisplayID = HIRESLACE_KEY;
  2302.         else
  2303.             DisplayID = HIRES_KEY;
  2304.  
  2305.         if(QueryOverscan(DisplayID,&DisplayClip,OSCAN_TEXT))
  2306.         {
  2307.             LONG Width = DisplayClip . MaxX - DisplayClip . MinX + 1;
  2308.  
  2309.             if(NewScreen . Width < Width)
  2310.             {
  2311.                 DisplayClip . MinX += (Width - NewScreen . Width) / 2;
  2312.                 DisplayClip . MaxX -= (Width - NewScreen . Width) / 2;
  2313.             }
  2314.  
  2315.             if(!(Screen = (struct Screen *)OpenScreenTags(&NewScreen,
  2316.                 SA_Behind,    TRUE,
  2317.                 SA_Quiet,    TRUE,
  2318.                 SA_ShowTitle,    FALSE,
  2319.                 SA_Depth,    1,
  2320.                 SA_DClip,    &DisplayClip,
  2321.                 SA_DisplayID,    DisplayID,
  2322.                 SA_SysFont,    NewScreen . Font ? 0 : 1,
  2323.             TAG_DONE)))
  2324.                 fatal("Could not open screen");
  2325.         }
  2326.         else
  2327.         {
  2328.             if(!(Screen = (struct Screen *)OpenScreenTags(&NewScreen,
  2329.                 SA_Behind,    TRUE,
  2330.                 SA_Quiet,    TRUE,
  2331.                 SA_ShowTitle,    FALSE,
  2332.                 SA_Depth,    1,
  2333.                 SA_Width,    NewScreen . Width,
  2334.                 SA_Height,    NewScreen . Height,
  2335.                 SA_DisplayID,    DisplayID,
  2336.                 SA_SysFont,    NewScreen . Font ? 0 : 1,
  2337.             TAG_DONE)))
  2338.                 fatal("Could not open screen");
  2339.         }
  2340.     }
  2341.  
  2342.     SetRGB4(&Screen -> ViewPort,0,0x0,0x0,0x0);
  2343.     SetRGB4(&Screen -> ViewPort,1,0xD,0xD,0xD);
  2344.  
  2345.         /* Clear new window defition. */
  2346.  
  2347.     memset(&NewWindow,0,sizeof(struct NewWindow));
  2348.  
  2349.         /* Fill in the new window definition. */
  2350.  
  2351.     NewWindow . Width    = Screen -> Width;
  2352.     NewWindow . Height    = Screen -> Height - SCREEN_MARGIN;
  2353.     NewWindow . LeftEdge    = 0;
  2354.     NewWindow . TopEdge    = SCREEN_MARGIN;
  2355.     NewWindow . DetailPen    = 1;
  2356.     NewWindow . BlockPen    = 0;
  2357.     NewWindow . IDCMPFlags    = IDCMP_RAWKEY | IDCMP_NEWSIZE;
  2358.     NewWindow . Flags    = WFLG_RMBTRAP | WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_BACKDROP;
  2359.     NewWindow . MinWidth    = NewWindow . Width;
  2360.     NewWindow . MinHeight    = NewWindow . Height;
  2361.     NewWindow . MaxWidth    = NewWindow . Width;
  2362.     NewWindow . MaxHeight    = NewWindow . Height;
  2363.     NewWindow . Screen    = Screen;
  2364.     NewWindow . Type    = CUSTOMSCREEN;
  2365.  
  2366.         /* Open the window. */
  2367.  
  2368.     if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
  2369.         fatal("Could not open window");
  2370.  
  2371.         /* Create the console write request. */
  2372.  
  2373.     if(!(ConRequest = (struct IOStdReq *)AllocMem(sizeof(struct IOStdReq),MEMF_ANY|MEMF_CLEAR)))
  2374.         fatal("No console request");
  2375.  
  2376.     if(!(InputEventBuffer = (STRPTR)AllocMem(INPUT_LENGTH,MEMF_ANY)))
  2377.         fatal("No input event buffer");
  2378.  
  2379.     if(!(InputEvent = (struct InputEvent *)AllocMem(sizeof(struct InputEvent),MEMF_ANY|MEMF_CLEAR)))
  2380.         fatal("No input event");
  2381.  
  2382.     if(OpenDevice("console.device",CONU_LIBRARY,ConRequest,NULL))
  2383.         fatal("No console.device");
  2384.  
  2385.     ConsoleDevice = ConRequest -> io_Device;
  2386.  
  2387.     WindowWidth = Window -> Width;
  2388.  
  2389.         /* Obtain rastport pointer. */
  2390.  
  2391.     RPort = Window -> RPort;
  2392.  
  2393.         /* Set text rendering mode. */
  2394.  
  2395.     SetAPen(RPort,ConFgPen = 1);
  2396.     SetBPen(RPort,ConBgPen = 0);
  2397.  
  2398.     SetDrMd(RPort,JAM2);
  2399.  
  2400.     PropFont    = Window -> WScreen -> RastPort . Font;
  2401.     FixedFont    = Window -> IFont;
  2402.  
  2403.     if(FixedFont -> tf_YSize != PropFont -> tf_YSize || h_type > 3)
  2404.         PropFont = FixedFont;
  2405.  
  2406.         /* Obtain the system default font dimensions. */
  2407.  
  2408.     TextFontHeight = FixedFont -> tf_YSize;
  2409.  
  2410.     SetFont(RPort,FixedFont);
  2411.  
  2412.         /* Look for the widest glyph. */
  2413.  
  2414.     for(Char = ' ' ; Char <= '~' ; Char++)
  2415.     {
  2416.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  2417.             TextFontWidth = Width;
  2418.  
  2419.         TextFontAverage += Width;
  2420.     }
  2421.  
  2422.     SetFont(RPort,ThisFont = PropFont);
  2423.  
  2424.         /* Look for the widest glyph. */
  2425.  
  2426.     for(Char = ' ' ; Char <= '~' ; Char++)
  2427.     {
  2428.         if((Width = ConCharWidth(Char)) > TextFontWidth)
  2429.             TextFontWidth = Width;
  2430.  
  2431.         TextFontAverage += Width;
  2432.     }
  2433.  
  2434.     TextFontAverage /= (2 * ('~' - ' ' + 1));
  2435.  
  2436.         /* Determine screen dimensions. */
  2437.  
  2438.     if(h_type > 3)
  2439.         screen_cols = Window -> Width / TextFontWidth;
  2440.     else
  2441.         screen_cols = Window -> Width;
  2442.  
  2443.     screen_rows = Window -> Height / TextFontHeight;
  2444.  
  2445.         /* Determine maximum cached line length. */
  2446.  
  2447.     ConLineMaxLength = screen_cols * TextFontWidth;
  2448.  
  2449.         /* Determine minimum number of characters to fit into a single line. */
  2450.  
  2451.     ConLineMinLength = Window -> Width / TextFontWidth;
  2452.  
  2453.         /* Allocate memory for line cache. */
  2454.  
  2455.     if(!(ConLine = (char *)AllocMem(ConLineMaxLength,NULL)))
  2456.         fatal("Not enough memory for line cache");
  2457.  
  2458.         /* Clear the screen and turn off the cursor. */
  2459.  
  2460.     clear_screen();
  2461.  
  2462.         /* Display startup message. */
  2463.  
  2464.     Len = strlen(TheStory);
  2465.  
  2466.     Move(RPort,(Window -> Width - TextLength(RPort,(STRPTR)TheStory,Len)) / 2,(Window -> Height - ThisFont -> tf_YSize) / 2 + ThisFont -> tf_Baseline);
  2467.     Text(RPort,(STRPTR)TheStory,Len);
  2468.  
  2469.     NewWidth = OldWidth = TextFontAverage;
  2470.  
  2471.         /* Start the timer. */
  2472.  
  2473.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2474.     TimeRequest -> tr_time . tv_secs    = 0;
  2475.     TimeRequest -> tr_time . tv_micro    = SECOND / 2;
  2476.  
  2477.     BeginIO(TimeRequest);
  2478.  
  2479.         /* Fill in new default window pointer. */
  2480.  
  2481.     ThisProcess -> pr_WindowPtr = (APTR)Window;
  2482.  
  2483.         /* Bring the new screen to the front. */
  2484.  
  2485.     ScreenToFront(Screen);
  2486. }
  2487.  
  2488.     /* restart_screen():
  2489.      *
  2490.      *    Reset the screen status to defaults.
  2491.      */
  2492.  
  2493. VOID
  2494. restart_screen()
  2495. {
  2496.     set_attribute(NORMAL);
  2497.  
  2498.     clear_screen();
  2499. }
  2500.  
  2501.     /* reset_screen():
  2502.      *
  2503.      *    Restore original screen contents, in our case we will have to
  2504.      *    free all the resources allocated by initialize_screen.
  2505.      */
  2506.  
  2507. VOID
  2508. reset_screen()
  2509. {
  2510.         /* Wait for key to be pressed. */
  2511.  
  2512.     if(Window)
  2513.     {
  2514.         ConPrintf("Press any key to exit.");
  2515.  
  2516.         input_character();
  2517.     }
  2518.  
  2519.         /* Free the console request. */
  2520.  
  2521.     if(ConRequest)
  2522.     {
  2523.             /* Did we open the device? If so, close it. */
  2524.  
  2525.         if(ConRequest -> io_Device)
  2526.             CloseDevice(ConRequest);
  2527.  
  2528.             /* Free the memory. */
  2529.  
  2530.         FreeMem(ConRequest,sizeof(struct IOStdReq));
  2531.     }
  2532.  
  2533.         /* Free the input conversion buffer. */
  2534.  
  2535.     if(InputEventBuffer)
  2536.         FreeMem(InputEventBuffer,INPUT_LENGTH);
  2537.  
  2538.         /* Free the fake inputevent. */
  2539.  
  2540.     if(InputEvent)
  2541.         FreeMem(InputEvent,sizeof(struct InputEvent));
  2542.  
  2543.         /* Free timer data. */
  2544.  
  2545.     if(TimeRequest)
  2546.     {
  2547.         if(TimeRequest -> tr_node . io_Device)
  2548.         {
  2549.             if(!CheckIO(TimeRequest))
  2550.                 AbortIO(TimeRequest);
  2551.  
  2552.             WaitIO(TimeRequest);
  2553.  
  2554.             CloseDevice(TimeRequest);
  2555.         }
  2556.  
  2557.         DeleteExtIO(TimeRequest);
  2558.     }
  2559.  
  2560.     if(TimePort)
  2561.         DeletePort(TimePort);
  2562.  
  2563.         /* Free line cache. */
  2564.  
  2565.     if(ConLine)
  2566.         FreeMem(ConLine,ConLineMaxLength);
  2567.  
  2568.         /* Close the window. */
  2569.  
  2570.     if(Window)
  2571.     {
  2572.         ScreenToBack(Screen);
  2573.  
  2574.         CloseWindow(Window);
  2575.     }
  2576.  
  2577.         /* Close the screen. */
  2578.  
  2579.     if(Screen)
  2580.     {
  2581.         ScreenToBack(Screen);
  2582.  
  2583.         CloseScreen(Screen);
  2584.     }
  2585.  
  2586.         /* Close libraries. */
  2587.  
  2588.     if(IconBase)
  2589.         CloseLibrary(IconBase);
  2590.  
  2591.     if(GfxBase)
  2592.         CloseLibrary(GfxBase);
  2593.  
  2594.     if(IntuitionBase)
  2595.         CloseLibrary(IntuitionBase);
  2596.  
  2597.         /* Free sound resources. */
  2598.  
  2599.     SoundExit();
  2600.  
  2601.         /* Restore window pointer. */
  2602.  
  2603.     if(ThisProcess)
  2604.         ThisProcess -> pr_WindowPtr = WindowPtr;
  2605.  
  2606. #ifdef __GNUC__
  2607.  
  2608.     {
  2609.         sigset_t trapped = TRAPPED_SIGNALS;
  2610.  
  2611.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2612.     }
  2613.  
  2614. #endif    /* __GNUC__ */
  2615. }
  2616.  
  2617.     /* clear_screen():
  2618.      *
  2619.      *    Clear the entire screen.
  2620.      */
  2621.  
  2622. VOID
  2623. clear_screen()
  2624. {
  2625.         /* Clear character cache. */
  2626.  
  2627.     ConLineLength = 0;
  2628.  
  2629.     if(CursorState)
  2630.     {
  2631.         ConCursorOff();
  2632.  
  2633.         SetAPen(RPort,0);
  2634.         RectFill(RPort,0,0,Window -> Width - 1,Window -> Height - 1);
  2635.         SetAPen(RPort,ConFgPen);
  2636.  
  2637.         ConCursorOn(CURSOR_NOCHANGE);
  2638.     }
  2639.     else
  2640.     {
  2641.         SetAPen(RPort,0);
  2642.         RectFill(RPort,0,0,Window -> Width - 1,Window -> Height - 1);
  2643.         SetAPen(RPort,ConFgPen);
  2644.     }
  2645.  
  2646.         /* Move to bottom line. */
  2647.  
  2648.     ConSet(0,(screen_rows - 1) * TextFontHeight,CURSOR_NOCHANGE);
  2649. }
  2650.  
  2651.     /* print_status(int argc,char **argv):
  2652.      *
  2653.      *    Print the status line (type 3 games only).
  2654.      *
  2655.      *    argv[0] : Location name
  2656.      *    argv[1] : Moves/Time
  2657.      *    argv[2] : Score
  2658.      *
  2659.      *    Depending on how many arguments are passed to this routine
  2660.      *    it is to print the status line. The rendering attributes
  2661.      *    and the status line window will be have been activated
  2662.      *    when this routine is called. It is to return FALSE if it
  2663.      *    cannot render the status line in which case the interpreter
  2664.      *    will use display_char() to render it on its own.
  2665.      *
  2666.      *    This routine has been provided in order to support
  2667.      *    proportional-spaced fonts.
  2668.      */
  2669.  
  2670. int
  2671. print_status(int argc,char *argv[])
  2672. {
  2673.     STATIC UBYTE    RightBuffer[170];
  2674.  
  2675.     STRPTR        Left,
  2676.             Right;
  2677.     LONG        LeftWidth,
  2678.             RightWidth;
  2679.     WORD        LeftLen,
  2680.             RightLen;
  2681.  
  2682.         /* Are we to change the font? */
  2683.  
  2684.     if(get_word(H_FLAGS) & FIXED_FONT_FLAG)
  2685.     {
  2686.         if(ThisFont != FixedFont)
  2687.             SetFont(RPort,ThisFont = FixedFont);
  2688.     }
  2689.     else
  2690.     {
  2691.         if(ThisFont != PropFont)
  2692.             SetFont(RPort,ThisFont = PropFont);
  2693.     }
  2694.  
  2695.         /* Set up the status bar, we will put both the
  2696.          * score and the moves on the left hand side
  2697.          * if present.
  2698.          */
  2699.  
  2700.     switch(argc)
  2701.     {
  2702.         case 0:    Left    = "";
  2703.             Right    = "";
  2704.             break;
  2705.  
  2706.         case 1:    Left    = argv[0];
  2707.             Right    = "";
  2708.             break;
  2709.  
  2710.         case 2:    Left    = argv[0];
  2711.             Right    = argv[1];
  2712.  
  2713.             break;
  2714.  
  2715.         case 3:    strcpy(RightBuffer,argv[1]);
  2716.             strcat(RightBuffer,"  ");
  2717.             strcat(RightBuffer,argv[2]);
  2718.  
  2719.             Left    = argv[0];
  2720.             Right    = RightBuffer;
  2721.  
  2722.             break;
  2723.     }
  2724.  
  2725.         /* Determine lengths of both strings. */
  2726.  
  2727.     LeftLen        = strlen(Left);
  2728.     RightLen    = strlen(Right);
  2729.  
  2730.         /* Determine pixel widths of both strings. */
  2731.  
  2732.     LeftWidth    = TextLength(RPort,Left,LeftLen);
  2733.     RightWidth    = TextLength(RPort,Right,RightLen);
  2734.  
  2735.         /* Fill in the space in between. */
  2736.  
  2737.     SetAPen(RPort,ConBgPen);
  2738.     RectFill(RPort,LeftWidth,0,Window -> Width - RightWidth - 1,ThisFont -> tf_YSize - 1);
  2739.     SetAPen(RPort,ConFgPen);
  2740.  
  2741.         /* Print the left hand side text. */
  2742.  
  2743.     Move(RPort,0,ThisFont -> tf_Baseline);
  2744.     Text(RPort,Left,LeftLen);
  2745.  
  2746.         /* Print the right hand side text. */
  2747.  
  2748.     Move(RPort,Window -> Width - RightWidth,ThisFont -> tf_Baseline);
  2749.     Text(RPort,Right,RightLen);
  2750.  
  2751.         /* Return success. */
  2752.  
  2753.     return(TRUE);
  2754. }
  2755.  
  2756.     /* select_status_window():
  2757.      *
  2758.      *    Move the cursor into the status bar area.
  2759.      */
  2760.  
  2761. VOID
  2762. select_status_window()
  2763. {
  2764.     ConFlush();
  2765.  
  2766.     save_cursor_position();
  2767.  
  2768.     ConSet(0,0,CURSOR_NOCHANGE);
  2769.  
  2770.     CurrentWindow = WINDOW_STATUS;
  2771. }
  2772.  
  2773.     /* select_text_window():
  2774.      *
  2775.      *    Move the cursor into the text window area.
  2776.      */
  2777.  
  2778. VOID
  2779. select_text_window()
  2780. {
  2781.     ConFlush();
  2782.  
  2783.     restore_cursor_position();
  2784.  
  2785.     CurrentWindow = WINDOW_TEXT;
  2786. }
  2787.  
  2788.     /* create_status_window():
  2789.      *
  2790.      *    Create the status window (not required by the Amiga
  2791.      *    implementation).
  2792.      */
  2793.  
  2794. VOID
  2795. create_status_window()
  2796. {
  2797. }
  2798.  
  2799.     /* delete_status_window():
  2800.      *
  2801.      *    Delete the status window (not required by the Amiga
  2802.      *    implementation).
  2803.      */
  2804.  
  2805. VOID
  2806. delete_status_window()
  2807. {
  2808. }
  2809.  
  2810.     /* clear_line():
  2811.      *
  2812.      *    Clear the contents of the current cursor line.
  2813.      */
  2814.  
  2815. VOID
  2816. clear_line()
  2817. {
  2818.     ConFlush();
  2819.  
  2820.     ConSet(0,CursorY,CURSOR_NOCHANGE);
  2821.  
  2822.     ConClearEOL();
  2823. }
  2824.  
  2825.     /* clear_text_window():
  2826.      *
  2827.      *    Clear the entire text window, don't touch the status
  2828.      *    bar area.
  2829.      */
  2830.  
  2831. VOID
  2832. clear_text_window()
  2833. {
  2834.     ConFlush();
  2835.  
  2836.     if(CursorState)
  2837.     {
  2838.         ConCursorOff();
  2839.  
  2840.         SetAPen(RPort,0);
  2841.         RectFill(RPort,0,status_size * TextFontHeight,Window -> Width - 1,(screen_rows - status_size) * TextFontHeight - 1);
  2842.         SetAPen(RPort,ConFgPen);
  2843.  
  2844.         ConCursorOn(CURSOR_NOCHANGE);
  2845.     }
  2846.     else
  2847.     {
  2848.         SetAPen(RPort,0);
  2849.         RectFill(RPort,0,status_size * TextFontHeight,Window -> Width - 1,(screen_rows - status_size) * TextFontHeight - 1);
  2850.         SetAPen(RPort,ConFgPen);
  2851.     }
  2852. }
  2853.  
  2854.     /* clear_status_window():
  2855.      *
  2856.      *    Clear the status bar area.
  2857.      */
  2858.  
  2859. VOID
  2860. clear_status_window()
  2861. {
  2862.     ConFlush();
  2863.  
  2864.     if(CursorState)
  2865.     {
  2866.         ConCursorOff();
  2867.  
  2868.         SetAPen(RPort,0);
  2869.         RectFill(RPort,0,0,Window -> Width - 1,status_size * TextFontHeight - 1);
  2870.         SetAPen(RPort,ConFgPen);
  2871.  
  2872.         ConCursorOn(CURSOR_NOCHANGE);
  2873.     }
  2874.     else
  2875.     {
  2876.         SetAPen(RPort,0);
  2877.         RectFill(RPort,0,0,Window -> Width - 1,status_size * TextFontHeight - 1);
  2878.         SetAPen(RPort,ConFgPen);
  2879.     }
  2880. }
  2881.  
  2882.     /* save_cursor_position():
  2883.      *
  2884.      *    Save the current cursor position.
  2885.      */
  2886.  
  2887. VOID
  2888. save_cursor_position()
  2889. {
  2890.     if(!SavedCursor)
  2891.     {
  2892.         SavedX        = CursorX;
  2893.         SavedY        = CursorY;
  2894.         SavedCursor    = TRUE;
  2895.     }
  2896. }
  2897.  
  2898.     /* restore_cursor_position():
  2899.      *
  2900.      *    Restore the previously saved cursor position.
  2901.      */
  2902.  
  2903. VOID
  2904. restore_cursor_position()
  2905. {
  2906.     if(SavedCursor)
  2907.     {
  2908.         ConSet(SavedX,SavedY,CURSOR_NOCHANGE);
  2909.  
  2910.         SavedCursor = FALSE;
  2911.     }
  2912. }
  2913.  
  2914.     /* move_cursor(int row,int col):
  2915.      *
  2916.      *    Move the cursor to a given position.
  2917.      */
  2918.  
  2919. VOID
  2920. move_cursor(int row,int col)
  2921. {
  2922.     ConFlush();
  2923.  
  2924.     ConSet((col - 1) * TextFontWidth,(row - 1) * TextFontHeight,CURSOR_NOCHANGE);
  2925. }
  2926.  
  2927.     /* set_attribute(int attribute):
  2928.      *
  2929.      *    Set a text rendering attribute.
  2930.      */
  2931.  
  2932. VOID
  2933. set_attribute(int attribute)
  2934. {
  2935.     ConFlush();
  2936.  
  2937.     switch(attribute)
  2938.     {
  2939.             /* Reversed character/cell colours */
  2940.  
  2941.         case REVERSE:        if(ConFgPen != 0)
  2942.                     {
  2943.                         SetAPen(RPort,ConFgPen = 0);
  2944.                         SetBPen(RPort,ConBgPen = 1);
  2945.                     }
  2946.  
  2947.                     break;
  2948.  
  2949.             /* Boldface */
  2950.  
  2951.         case BOLD:        SetSoftStyle(RPort,FSF_BOLD,AskSoftStyle(RPort));
  2952.  
  2953.                     if(ConFgPen != 1)
  2954.                     {
  2955.                         SetAPen(RPort,ConFgPen = 1);
  2956.                         SetBPen(RPort,ConBgPen = 0);
  2957.                     }
  2958.  
  2959.                     break;
  2960.  
  2961.             /* Italics */
  2962.  
  2963.         case BLINK:        SetSoftStyle(RPort,FSF_ITALIC,AskSoftStyle(RPort));
  2964.  
  2965.                     if(ConFgPen != 1)
  2966.                     {
  2967.                         SetAPen(RPort,ConFgPen = 1);
  2968.                         SetBPen(RPort,ConBgPen = 0);
  2969.                     }
  2970.  
  2971.                     break;
  2972.  
  2973.             /* Underlined */
  2974.  
  2975.         case UNDERSCORE:    SetSoftStyle(RPort,FSF_UNDERLINED,AskSoftStyle(RPort));
  2976.  
  2977.                     if(ConFgPen != 1)
  2978.                     {
  2979.                         SetAPen(RPort,ConFgPen = 1);
  2980.                         SetBPen(RPort,ConBgPen = 0);
  2981.                     }
  2982.  
  2983.                     break;
  2984.  
  2985.             /* Default (= Reset) */
  2986.  
  2987.         default:        SetSoftStyle(RPort,FS_NORMAL,AskSoftStyle(RPort));
  2988.  
  2989.                     if(ConFgPen != 1)
  2990.                     {
  2991.                         SetAPen(RPort,ConFgPen = 1);
  2992.                         SetBPen(RPort,ConBgPen = 0);
  2993.                     }
  2994.  
  2995.                     break;
  2996.     }
  2997.  
  2998.         /* Remember current attribute. */
  2999.  
  3000.     CurrentAttribute = attribute;
  3001. }
  3002.  
  3003.     /* fit_line(const char *line,int pos,int max):
  3004.      *
  3005.      *    This routine determines whether a line of text will still fit
  3006.      *    on the screen.
  3007.      *
  3008.      *    line : Line of text to test.
  3009.      *    pos  : Length of text line (in characters).
  3010.      *    max  : Maximum number of characters to fit on the screen.
  3011.      */
  3012.  
  3013. int
  3014. fit_line(const char *line,int pos,int max)
  3015. {
  3016.         /* For type 4 games just compare the current and maximum line width. */
  3017.  
  3018.     if(h_type > 3)
  3019.         return(pos < max);
  3020.     else
  3021.     {
  3022.         if(pos > ConLineMinLength)
  3023.         {
  3024.             if(get_word(H_FLAGS) & FIXED_FONT_FLAG)
  3025.             {
  3026.                 if(ThisFont != FixedFont)
  3027.                 {
  3028.                     ConFlush();
  3029.  
  3030.                     SetFont(RPort,ThisFont = FixedFont);
  3031.                 }
  3032.             }
  3033.             else
  3034.             {
  3035.                 if(ThisFont != PropFont)
  3036.                 {
  3037.                     ConFlush();
  3038.  
  3039.                     SetFont(RPort,ThisFont = PropFont);
  3040.                 }
  3041.             }
  3042.  
  3043.             return(TextLength(RPort,(STRPTR)line,pos) + TextFontWidth < Window -> Width);
  3044.                 }
  3045.         else
  3046.             return(TRUE);
  3047.     }
  3048. }
  3049.  
  3050.     /* display_char(int c):
  3051.      *
  3052.      *    Display a single character (characters are cached in
  3053.      *    order to speed up text display).
  3054.      */
  3055.  
  3056. VOID
  3057. display_char(int c)
  3058. {
  3059.     if(get_word(H_FLAGS) & FIXED_FONT_FLAG)
  3060.     {
  3061.         if(ThisFont != FixedFont)
  3062.         {
  3063.             ConFlush();
  3064.  
  3065.             SetFont(RPort,ThisFont = FixedFont);
  3066.         }
  3067.     }
  3068.     else
  3069.     {
  3070.         if(ThisFont != PropFont)
  3071.         {
  3072.             ConFlush();
  3073.  
  3074.             SetFont(RPort,ThisFont = PropFont);
  3075.         }
  3076.     }
  3077.  
  3078.     if(c >= ' ')
  3079.     {
  3080.             /* Cache the character. */
  3081.  
  3082.         ConLine[ConLineLength] = c;
  3083.  
  3084.             /* If the line cache is full, flush it. */
  3085.  
  3086.         if(ConLineLength++ == ConLineMaxLength)
  3087.             ConFlush();
  3088.     }
  3089.     else
  3090.     {
  3091.         ConFlush();
  3092.  
  3093.         switch(c)
  3094.         {
  3095.             case '\n':    ConSet(0,CursorY + TextFontHeight,CURSOR_NOCHANGE);
  3096.                     break;
  3097.  
  3098.             case '\r':    ConSet(0,CursorY,CURSOR_NOCHANGE);
  3099.                     break;
  3100.  
  3101.             case '\a':    DisplayBeep(Window -> WScreen);
  3102.                     break;
  3103.  
  3104.             default:    break;
  3105.         }
  3106.     }
  3107. }
  3108.  
  3109.     /* fatal(const char *s):
  3110.      *
  3111.      *    Display a fatal error message.
  3112.      */
  3113.  
  3114. VOID
  3115. fatal(const char *s)
  3116. {
  3117.     ConFlush();
  3118.  
  3119.         /* If the console window is available, print the message
  3120.          * into it, else send it to the shell window.
  3121.          */
  3122.  
  3123.     if(Window)
  3124.         ConPrintf("Fatal error: %s",s);
  3125.     else
  3126.     {
  3127.         if(!WBenchMsg)
  3128.             printf("\nFatal error: %s\a\n",s);
  3129.     }
  3130.  
  3131.     reset_screen();
  3132.  
  3133.     exit(RETURN_ERROR);
  3134. }
  3135.  
  3136.     /* input_character():
  3137.      *
  3138.      *    Input a single character.
  3139.      */
  3140.  
  3141. char
  3142. input_character()
  3143. {
  3144.     register UBYTE    Char;
  3145.     register BYTE    Done = FALSE;
  3146.  
  3147.     ConFlush();
  3148.  
  3149.     ConCursorOn(CURSOR_AVERAGE);
  3150.  
  3151.     do
  3152.     {
  3153.         switch(Char = ConGetChar(TRUE))
  3154.         {
  3155.                 /* If it's a suitable character, terminate input. */
  3156.  
  3157.             case '\b':
  3158.             case '\r':    Done = TRUE;
  3159.                     break;
  3160.  
  3161.             default:    if(Char >= 32 && Char < 127)
  3162.                         Done = TRUE;
  3163.  
  3164.                     break;
  3165.         }
  3166.     }
  3167.     while(!Done);
  3168.  
  3169.         /* Turn off the cursor. */
  3170.  
  3171.     ConCursorOff();
  3172.  
  3173.     return((char)Char);
  3174. }
  3175.  
  3176.     /* input_line():
  3177.      *
  3178.      *    Input a single line.
  3179.      */
  3180.  
  3181. VOID
  3182. input_line()
  3183. {
  3184.     STATIC char Prompt[140];
  3185.  
  3186.     if(ConLineLength)
  3187.     {
  3188.         memcpy(Prompt,ConLine,ConLineLength);
  3189.  
  3190.         Prompt[ConLineLength] = 0;
  3191.     }
  3192.     else
  3193.         Prompt[0] = 0;
  3194.  
  3195.     ConFlush();
  3196.  
  3197.         /* Read a line of text, input[0] = maximum length,
  3198.          * input[1] = number of characters read.
  3199.          */
  3200.  
  3201.     input[1] = ConInput(Prompt,&input[2],input[0],TRUE);
  3202.  
  3203.         /* Turn off the cursor. */
  3204.  
  3205.     ConCursorOff();
  3206.  
  3207.     scroll_line();
  3208. }
  3209.  
  3210.     /* scroll_line():
  3211.      *
  3212.      *    Scroll the text area one line up.
  3213.      */
  3214.  
  3215. VOID
  3216. scroll_line()
  3217. {
  3218.     ConFlush();
  3219.  
  3220.     ConScrollUp();
  3221. }
  3222.  
  3223.     /* process_arguments(int argc, char *argv[]):
  3224.      *
  3225.      *    Do any argument preprocessing necessary before the game is
  3226.      *    started. This may include selecting a specific game file or
  3227.      *    setting interface-specific options.
  3228.      */
  3229.  
  3230. void
  3231. process_arguments(int argc, char *argv[])
  3232. {
  3233.     int Len;
  3234.  
  3235.     if(argc > 1)
  3236.     {
  3237.         if(!strcmp(argv[1],"?"))
  3238.         {
  3239.             printf("Usage: %s [Story file name] [Saved game file name]\n",argv[0]);
  3240.  
  3241.             exit(RETURN_WARN);
  3242.         }
  3243.         else
  3244.             StoryName = argv[1];
  3245.  
  3246.         if(argc > 2)
  3247.             restore_name = argv[2];
  3248.     }
  3249.     else
  3250.         StoryName = "Story.Data";
  3251.  
  3252.     if(argc)
  3253.         InterpreterName = argv[0];
  3254.     else
  3255.     {
  3256.         WBenchMsg = (struct WBStartup *)argv;
  3257.  
  3258.         InterpreterName = WBenchMsg -> sm_ArgList[0] . wa_Name;
  3259.  
  3260.         if(IconBase = OpenLibrary("icon.library",LIB_VERSION))
  3261.         {
  3262.             struct DiskObject *Icon;
  3263.  
  3264.             if(Icon = GetDiskObject(InterpreterName))
  3265.             {
  3266.                 char     Buffer[5],
  3267.                     *Type;
  3268.                 int     i;
  3269.  
  3270.                     /* Does it have a filetype info attached? */
  3271.  
  3272.                 if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"STORY"))
  3273.                 {
  3274.                     if(StoryName = (STRPTR)malloc(strlen(Type) + 1))
  3275.                         strcpy(StoryName,Type);
  3276.                     else
  3277.                         StoryName = "Story.Data";
  3278.                 }
  3279.  
  3280.                     /* Check for function key
  3281.                      * defintions and set them
  3282.                      * if approriate.
  3283.                      */
  3284.  
  3285.                 for(i = 0 ; i < NUM_FKEYS ; i++)
  3286.                 {
  3287.                         /* Build fkey string. */
  3288.  
  3289.                     sprintf(Buffer,"F0%2d",i + 1);
  3290.  
  3291.                         /* See if we can find it. */
  3292.  
  3293.                     if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,Buffer))
  3294.                         ConSetKey(i,Type,strlen(Type));
  3295.                     else
  3296.                         ConSetKey(i,"",0);
  3297.                 }
  3298.  
  3299.                     /* Free the icon. */
  3300.  
  3301.                 FreeDiskObject(Icon);
  3302.             }
  3303.  
  3304.             if(WBenchMsg -> sm_NumArgs > 1)
  3305.             {
  3306.                 char    *Type;
  3307.                 int     i;
  3308.  
  3309.                 for(i = 0 ; i < WBenchMsg -> sm_NumArgs ; i++)
  3310.                 {
  3311.                     CurrentDir(WBenchMsg -> sm_ArgList[i] . wa_Lock);
  3312.  
  3313.                     if(Icon = GetDiskObject(WBenchMsg -> sm_ArgList[i] . wa_Name))
  3314.                     {
  3315.                         /* Does it have a filetype info attached? */
  3316.  
  3317.                         if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
  3318.                         {
  3319.                             /* Is it a bookmark file? */
  3320.  
  3321.                             if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ZIP"))
  3322.                             {
  3323.                                 restore_name = WBenchMsg -> sm_ArgList[i] . wa_Name;
  3324.  
  3325.                                 if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"STORY"))
  3326.                                 {
  3327.                                     BPTR File;
  3328.  
  3329.                                         /* Try to open the file, this is
  3330.                                          * easier than locking it, allocating
  3331.                                          * a fileinfo, reading it and then
  3332.                                          * to clean up again.
  3333.                                          */
  3334.  
  3335.                                     if(File = Open(Type,MODE_OLDFILE))
  3336.                                     {
  3337.                                         char *NewName;
  3338.  
  3339.                                         Close(File);
  3340.  
  3341.                                         if(NewName = (STRPTR)malloc(strlen(Type) + 1))
  3342.                                         {
  3343.                                             strcpy(NewName,Type);
  3344.  
  3345.                                             StoryName = NewName;
  3346.                                         }
  3347.                                     }
  3348.                                 }
  3349.  
  3350.                                 FreeDiskObject(Icon);
  3351.                                 break;
  3352.                             }
  3353.  
  3354.                             if(MatchToolValue(Type,"STORY"))
  3355.                             {
  3356.                                 BPTR File;
  3357.  
  3358.                                     /* Try to open the file, this is
  3359.                                      * easier than locking it, allocating
  3360.                                      * a fileinfo, reading it and then
  3361.                                      * to clean up again.
  3362.                                      */
  3363.  
  3364.                                 if(File = Open(WBenchMsg -> sm_ArgList[i] . wa_Name,MODE_OLDFILE))
  3365.                                 {
  3366.                                     char *NewName;
  3367.  
  3368.                                     Close(File);
  3369.  
  3370.                                     if(NewName = (STRPTR)malloc(strlen(WBenchMsg -> sm_ArgList[i] . wa_Name) + 1))
  3371.                                     {
  3372.                                         strcpy(NewName,WBenchMsg -> sm_ArgList[i] . wa_Name);
  3373.  
  3374.                                         StoryName = NewName;
  3375.                                     }
  3376.                                 }
  3377.  
  3378.                                 FreeDiskObject(Icon);
  3379.                                 break;
  3380.                             }
  3381.                         }
  3382.  
  3383.                             /* Free the icon. */
  3384.  
  3385.                         FreeDiskObject(Icon);
  3386.                     }
  3387.                 }
  3388.             }
  3389.  
  3390.             CloseLibrary(IconBase);
  3391.  
  3392.             IconBase = NULL;
  3393.         }
  3394.     }
  3395.  
  3396.     open_story(StoryName);
  3397.  
  3398.     Len = strlen(StoryName);
  3399.  
  3400.         /* Make a copy of the game name. */
  3401.  
  3402.     if(SoundName = malloc(Len + 40))
  3403.     {
  3404.         strcpy(SoundName,StoryName);
  3405.  
  3406.             /* Does the sound file name have any
  3407.              * length, i.e. is it a real name?
  3408.              */
  3409.  
  3410.         if(Len)
  3411.         {
  3412.             int i;
  3413.  
  3414.                 /* Starting from the end of the
  3415.                  * file name look for the first
  3416.                  * path character.
  3417.                  */
  3418.  
  3419.             for(i = Len - 1 ; i >= 0 ; i--)
  3420.             {
  3421.                     /* Is it a path name seperation
  3422.                      * character?
  3423.                      */
  3424.  
  3425.                 if(SoundName[i] == '/' || SoundName[i] == ':')
  3426.                 {
  3427.                         /* Append the sound directory
  3428.                          * name to the string.
  3429.                          */
  3430.  
  3431.                     SoundPath = &SoundName[i + 1];
  3432.  
  3433.                         /* We're finished. */
  3434.  
  3435.                     break;
  3436.                 }
  3437.             }
  3438.         }
  3439.  
  3440.             /* If no proper subdirectory name was
  3441.              * to be found, override the entire
  3442.              * string.
  3443.              */
  3444.  
  3445.         if(!SoundPath)
  3446.             SoundPath = SoundName;
  3447.     }
  3448. }
  3449.  
  3450.     /* file_cleanup(const char *file_name, int flag):
  3451.      *
  3452.      *    Perform certain actions after a game file is saved (flag = 1)
  3453.      *    or restored (flag = 0).
  3454.      */
  3455.  
  3456. void
  3457. file_cleanup(const char *file_name, int flag)
  3458. {
  3459.         /* Was the file saved or restored? */
  3460.  
  3461.     if(flag == GAME_SAVE)
  3462.     {
  3463.             /* Clear the `executable' bit. */
  3464.  
  3465.         SetProtection((char *)file_name,FIBF_EXECUTE);
  3466.  
  3467.         if(IconBase)
  3468.         {
  3469.             struct DiskObject *Icon;
  3470.  
  3471.                 /* Get the default icon. */
  3472.  
  3473.             if(Icon = GetDiskObject("Icon.Data"))
  3474.             {
  3475.                 char **ToolTypes;
  3476.  
  3477.                     /* Create the tool type array. */
  3478.  
  3479.                 if(ToolTypes = (char **)malloc(sizeof(char *) * (NUM_FKEYS + 3)))
  3480.                 {
  3481.                     int i,j = 0;
  3482.  
  3483.                         /* Fill in the file type. */
  3484.  
  3485.                     ToolTypes[j++] = "FILETYPE=BOOKMARK|ZIP";
  3486.  
  3487.                         /* Add the story file name. */
  3488.  
  3489.                     if(ToolTypes[j] = malloc(strlen(StoryName) + 7))
  3490.                         sprintf(ToolTypes[j++],"STORY=%s",StoryName);
  3491.  
  3492.                         /* Add the function key definitions if any. */
  3493.  
  3494.                     for(i = 0 ; i < NUM_FKEYS ; i++)
  3495.                     {
  3496.                         if(FunctionKeys[i] . Len)
  3497.                         {
  3498.                             if(ToolTypes[j] = malloc(FunctionKeys[i] . Len + 5))
  3499.                                 sprintf(ToolTypes[j++],"F%02d=%s",i + 1,FunctionKeys[i] . Buffer);
  3500.                         }
  3501.                     }
  3502.  
  3503.                         /* Terminat the tool type array. */
  3504.  
  3505.                     ToolTypes[j] = NULL;
  3506.  
  3507.                         /* Fill in the icon data. */
  3508.  
  3509.                     Icon -> do_DefaultTool    = InterpreterName;
  3510.                     Icon -> do_ToolTypes    = ToolTypes;
  3511.                     Icon -> do_StackSize    = ThisProcess -> pr_StackSize;
  3512.                     Icon -> do_CurrentX    = NO_ICON_POSITION;
  3513.                     Icon -> do_CurrentY    = NO_ICON_POSITION;
  3514.  
  3515.                         /* Create the icon. */
  3516.  
  3517.                     if(!PutDiskObject((char *)file_name,Icon))
  3518.                         output_stringnl("[Error creating icon file]");
  3519.  
  3520.                         /* Free the tool type entries. */
  3521.  
  3522.                     for(i = 1 ; i < j ; i++)
  3523.                         free(ToolTypes[i]);
  3524.  
  3525.                         /* Free the tool type array. */
  3526.  
  3527.                     free(ToolTypes);
  3528.                 }
  3529.  
  3530.                     /* Free the icon. */
  3531.  
  3532.                 FreeDiskObject(Icon);
  3533.             }
  3534.             else
  3535.                 output_stringnl("[No icon]");
  3536.         }
  3537.         else
  3538.             output_stringnl("[No icon]");
  3539.     }
  3540.  
  3541.     if(flag == GAME_RESTORE)
  3542.     {
  3543.         if(IconBase)
  3544.         {
  3545.             struct DiskObject *Icon;
  3546.  
  3547.                 /* Get the file icon. */
  3548.  
  3549.             if(Icon = GetDiskObject((char *)file_name))
  3550.             {
  3551.                 char     Buffer[5],
  3552.                     *Type;
  3553.                 int     i;
  3554.  
  3555.                     /* Does it have a filetype info attached? */
  3556.  
  3557.                 if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,"FILETYPE"))
  3558.                 {
  3559.                         /* Is it a bookmark file? */
  3560.  
  3561.                     if(MatchToolValue(Type,"BOOKMARK") && MatchToolValue(Type,"ZIP"))
  3562.                     {
  3563.                             /* Check for function key
  3564.                              * defintions and set them
  3565.                              * if approriate.
  3566.                              */
  3567.  
  3568.                         for(i = 0 ; i < NUM_FKEYS ; i++)
  3569.                         {
  3570.                                 /* Build fkey string. */
  3571.  
  3572.                             sprintf(Buffer,"F%02d",i + 1);
  3573.  
  3574.                                 /* See if we can find it. */
  3575.  
  3576.                             if(Type = FindToolType((STRPTR *)Icon -> do_ToolTypes,Buffer))
  3577.                                 ConSetKey(i,Type,strlen(Type));
  3578.                             else
  3579.                                 ConSetKey(i,"",0);
  3580.                         }
  3581.                     }
  3582.                 }
  3583.  
  3584.                     /* Free the icon. */
  3585.  
  3586.                 FreeDiskObject(Icon);
  3587.             }
  3588.             else
  3589.                 output_stringnl("[No icon]");
  3590.         }
  3591.         else
  3592.             output_stringnl("[No icon]");
  3593.     }
  3594. }
  3595.  
  3596.     /* sound(int argc, zword_t * argv):
  3597.      *
  3598.      *    Replay a sound file or just a bell (^G) signal:
  3599.      *
  3600.      *    argc = 1: Play bell signal.
  3601.      *
  3602.      *    argc = 2: argv[0] = 0
  3603.      *              argv[1] = 3
  3604.      *
  3605.      *              Stop playing current sound.
  3606.      *
  3607.      *    argc = 2: argv[0] = 0
  3608.      *              argv[1] = 4
  3609.      *
  3610.      *              Free allocated resources.
  3611.      *
  3612.      *    argc = 3: argv[0] = ID# of sound file to replay.
  3613.      *              argv[1] = 2
  3614.      *              argv[2] = Volume to replay sound with, this value
  3615.      *                        can range between 1 and 8.
  3616.      */
  3617.  
  3618. void
  3619. sound(int argc, zword_t * argv)
  3620. {
  3621.     if(argc == 1)
  3622.     {
  3623.         int Count = argv[0];
  3624.  
  3625.         while(Count--)
  3626.         {
  3627.             DisplayBeep(Window -> WScreen);
  3628.  
  3629.             if(Count)
  3630.                 Delay(TICKS_PER_SECOND / 2);
  3631.         }
  3632.     }
  3633.     else
  3634.     {
  3635.             /* Is the sound name buffer available? */
  3636.  
  3637.         if(SoundName)
  3638.         {
  3639.             register BOOL GotSound;
  3640.  
  3641.                 /* What are we to do next? */
  3642.  
  3643.             switch(argv[1])
  3644.             {
  3645.                     /* If a new sound is to be replayed, stop
  3646.                      * the current sound.
  3647.                      */
  3648.  
  3649.                 case 2:    if(argv[0] != SoundNumber && SoundNumber != -1 && SoundControlRequest)
  3650.                     {
  3651.                         SoundAbort();
  3652.  
  3653.                             /* Free previously allocated sound data. */
  3654.  
  3655.                         if(SoundData && SoundLength)
  3656.                         {
  3657.                                 /* Free it. */
  3658.  
  3659.                             FreeMem(SoundData,SoundLength);
  3660.  
  3661.                                 /* Leave no traces. */
  3662.  
  3663.                             SoundData    = NULL;
  3664.                             SoundLength    = 0;
  3665.                         }
  3666.  
  3667.                         SoundNumber = -1;
  3668.                     }
  3669.  
  3670.                         /* Make sure that we have the resources we need,
  3671.                          * either allocate them or rely on the fact that
  3672.                          * the previous call to this routine had already
  3673.                          * triggered the allocation.
  3674.                          */
  3675.  
  3676.                     if(!SoundControlRequest)
  3677.                         GotSound = SoundInit();
  3678.                     else
  3679.                         GotSound = TRUE;
  3680.  
  3681.                         /* Do we have the resources or not? */
  3682.  
  3683.                     if(GotSound)
  3684.                     {
  3685.                             /* If we are to replay the same sound as we
  3686.                              * did before, we are probably to change the
  3687.                              * replay volume.
  3688.                              */
  3689.  
  3690.                         if(SoundNumber == argv[0] && SoundNumber != -1)
  3691.                         {
  3692.                                 /* Is the sound still playing? If so,
  3693.                                  * change the volume, else restart
  3694.                                  * it with the new volume.
  3695.                                  */
  3696.  
  3697.                             if(!CheckIO((struct IORequest *)SoundRequestLeft))
  3698.                             {
  3699.                                     /* Set up new volume. */
  3700.  
  3701.                                 SoundControlRequest -> ioa_Request . io_Command    = ADCMD_PERVOL;
  3702.                                 SoundControlRequest -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  3703.                                 SoundControlRequest -> ioa_Volume        = argv[2] * 8;
  3704.  
  3705.                                     /* Tell the device to make the change. */
  3706.  
  3707.                                 SendIO((struct IORequest *)SoundControlRequest);
  3708.                                 WaitIO((struct IORequest *)SoundControlRequest);
  3709.                             }
  3710.                             else
  3711.                             {
  3712.                                     /* Wait for requests to return. */
  3713.  
  3714.                                 SoundAbort();
  3715.  
  3716.                                     /* Set up new volume. */
  3717.  
  3718.                                 SoundRequestLeft  -> ioa_Volume = argv[2] * 8;
  3719.                                 SoundRequestRight -> ioa_Volume = argv[2] * 8;
  3720.  
  3721.                                     /* Stop the sound. */
  3722.  
  3723.                                 SoundStop();
  3724.  
  3725.                                     /* Queue the sound. */
  3726.  
  3727.                                 BeginIO((struct IORequest *)SoundRequestLeft);
  3728.                                 BeginIO((struct IORequest *)SoundRequestRight);
  3729.  
  3730.                                     /* Start the sound. */
  3731.  
  3732.                                 SoundStart();
  3733.                             }
  3734.                         }
  3735.                         else
  3736.                         {
  3737.                                 /* The sound file header. */
  3738.  
  3739.                             struct
  3740.                             {
  3741.                                 UBYTE    Reserved1[2];
  3742.                                 BYTE    Times;        /* How many times to play (0 = continuously). */
  3743.                                 UBYTE    Rate[2];    /* Replay rate (note: little endian). */
  3744.                                 UBYTE    Reserved2[3];
  3745.                                 UWORD    PlayLength;    /* Length of sound to replay. */
  3746.                             } SoundHeader;
  3747.  
  3748.                                 /* Sound file handle and name buffer. */
  3749.  
  3750.                             FILE *SoundFile;
  3751.  
  3752.                                 /* Cancel the argv[0] of the previously loaded
  3753.                                  * sound in case the load fails.
  3754.                                  */
  3755.  
  3756.                             SoundNumber = -1;
  3757.  
  3758.                                 /* Set up the sound file name. */
  3759.  
  3760.                             sprintf(SoundPath,"sound/s%d.dat",argv[0]);
  3761.  
  3762.                                 /* Open the file for reading. */
  3763.  
  3764.                             if(SoundFile = fopen(SoundName,"rb"))
  3765.                             {
  3766.                                     /* Read the file header. */
  3767.  
  3768.                                 if(fread(&SoundHeader,sizeof(SoundHeader),1,SoundFile) == 1)
  3769.                                 {
  3770.                                         /* Remember the sound file length. */
  3771.  
  3772.                                     SoundLength = SoundHeader . PlayLength;
  3773.  
  3774.                                         /* Allocate chip ram for the sound data. */
  3775.  
  3776.                                     if(SoundData = (APTR)AllocMem(SoundLength,MEMF_CHIP))
  3777.                                     {
  3778.                                             /* Read the sound data. */
  3779.  
  3780.                                         if(fread(SoundData,SoundLength,1,SoundFile) == 1)
  3781.                                         {
  3782.                                                 /* Turn the replay rate into a
  3783.                                                  * sensible argv[0].
  3784.                                                  */
  3785.  
  3786.                                             ULONG Rate = (GfxBase -> DisplayFlags & PAL ? 3546895 : 3579545) / ((((UWORD)SoundHeader . Rate[1]) << 8) | SoundHeader . Rate[0]);
  3787.  
  3788.                                                 /* Set up the left channel. */
  3789.  
  3790.                                             SoundRequestLeft -> ioa_Request . io_Command    = CMD_WRITE;
  3791.                                             SoundRequestLeft -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  3792.                                             SoundRequestLeft -> ioa_Period            = Rate;
  3793.                                             SoundRequestLeft -> ioa_Volume            = argv[2] * 8;
  3794.                                             SoundRequestLeft -> ioa_Cycles            = SoundHeader . Times;
  3795.                                             SoundRequestLeft -> ioa_Data            = SoundData;
  3796.                                             SoundRequestLeft -> ioa_Length            = SoundLength;
  3797.  
  3798.                                                 /* Set up the right channel. */
  3799.  
  3800.                                             SoundRequestRight -> ioa_Request . io_Command    = CMD_WRITE;
  3801.                                             SoundRequestRight -> ioa_Request . io_Flags    = ADIOF_PERVOL;
  3802.                                             SoundRequestRight -> ioa_Period            = Rate;
  3803.                                             SoundRequestRight -> ioa_Volume            = argv[2] * 8;
  3804.                                             SoundRequestRight -> ioa_Cycles            = SoundHeader . Times;
  3805.                                             SoundRequestRight -> ioa_Data            = SoundData;
  3806.                                             SoundRequestRight -> ioa_Length            = SoundLength;
  3807.  
  3808.                                                 /* Set up the control request. */
  3809.  
  3810.                                             SoundControlRequest -> ioa_Period        = Rate;
  3811.  
  3812.                                                 /* Stop playing any sound. */
  3813.  
  3814.                                             SoundStop();
  3815.  
  3816.                                                 /* Queue the sound. */
  3817.  
  3818.                                             BeginIO((struct IORequest *)SoundRequestLeft);
  3819.                                             BeginIO((struct IORequest *)SoundRequestRight);
  3820.  
  3821.                                                 /* Play the sound. */
  3822.  
  3823.                                             SoundStart();
  3824.  
  3825.                                                 /* Remember the argv[0] of the current sound. */
  3826.  
  3827.                                             SoundNumber = argv[0];
  3828.                                         }
  3829.                                         else
  3830.                                         {
  3831.                                                 /* The load failed, free the audio memory. */
  3832.  
  3833.                                             FreeMem(SoundData,SoundLength);
  3834.  
  3835.                                                 /* Leave no traces. */
  3836.  
  3837.                                             SoundData    = NULL;
  3838.                                             SoundLength    = 0;
  3839.                                         }
  3840.                                     }
  3841.                                 }
  3842.  
  3843.                                     /* Close the sound file. */
  3844.  
  3845.                                 fclose(SoundFile);
  3846.                             }
  3847.                         }
  3848.                     }
  3849.  
  3850.                     break;
  3851.  
  3852.                     /* Free resources. */
  3853.  
  3854.                 case 3:    SoundExit();
  3855.  
  3856.                     break;
  3857.             }
  3858.         }
  3859.     }
  3860. }
  3861.  
  3862.     /* get_file_name(char *file_name, char *default_name, int flag):
  3863.      *
  3864.      *    Return the name of a file. Flag can be one of: GAME_SAVE, GAME_RESTORE or
  3865.      *    GAME_SCRIPT.
  3866.      */
  3867.  
  3868. int
  3869. get_file_name(char *file_name, char *default_name, int flag)
  3870. {
  3871.     int     saved_scripting_disable = scripting_disable,
  3872.          columns = (screen_cols > 127) ? 127 : screen_cols,
  3873.          status = TRUE;
  3874.     FILE    *tfp;
  3875.     char     c;
  3876.  
  3877.     if(!default_name[0])
  3878.     {
  3879.         if(flag == GAME_SCRIPT)
  3880.             strcpy(default_name,"PRT:");
  3881.         else
  3882.             strcpy(default_name,"Story.Save");
  3883.     }
  3884.  
  3885.     scripting_disable = ON;
  3886.  
  3887.     output_stringnl("Enter a file name.");
  3888.     output_string("(Default is \"");
  3889.     output_string(default_name);
  3890.     output_string("\") >");
  3891.  
  3892.     input[0] = (char) (columns - RIGHT_MARGIN - 1 - sizeof("(Default is \"") - strlen(default_name) - sizeof("\"): "));
  3893.  
  3894.     input_line();
  3895.  
  3896.     if(input[1])
  3897.     {
  3898.         input[input[1] + 2] = '\0';
  3899.  
  3900.         strcpy(file_name, &input[2]);
  3901.     }
  3902.     else
  3903.         strcpy(file_name, default_name);
  3904.  
  3905.     if(flag)
  3906.     {
  3907.         if(tfp = fopen(file_name,"r"))
  3908.         {
  3909.             fclose(tfp);
  3910.  
  3911.             output_string("You are about to write over an existing file.  Proceed? (Y/N) >");
  3912.  
  3913.             do
  3914.                 c = input_character();
  3915.             while(toupper(c) != 'Y' && toupper(c) != 'N');
  3916.  
  3917.             display_char(c);
  3918.  
  3919.             scroll_line();
  3920.  
  3921.             if(c == 'N')
  3922.                 status = FALSE;
  3923.         }
  3924.     }
  3925.  
  3926.     scripting_disable = saved_scripting_disable;
  3927.  
  3928.     return(status);
  3929. }
  3930.